package cn.congine.wizarpos.mall.action;

import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import cn.congine.wizarpos.mall.common.RespMessage;
import cn.congine.wizarpos.mall.model.open.AccessTokenInput;
import cn.congine.wizarpos.mall.model.open.AccessTokenOutput;
import cn.congine.wizarpos.mall.model.open.Address;
import cn.congine.wizarpos.mall.model.open.AddressEditInput;
import cn.congine.wizarpos.mall.model.open.AddressEditOutput;
import cn.congine.wizarpos.mall.model.open.AddressGainInput;
import cn.congine.wizarpos.mall.model.open.AddressGainOutput;
import cn.congine.wizarpos.mall.model.open.CheckVerificationCodeInput;
import cn.congine.wizarpos.mall.model.open.CheckVerificationCodeOutput;
import cn.congine.wizarpos.mall.model.open.CommonResultOutput;
import cn.congine.wizarpos.mall.model.open.DzxTranLogInput;
import cn.congine.wizarpos.mall.model.open.DzxTranLogOutput;
import cn.congine.wizarpos.mall.model.open.DzxTranLogView;
import cn.congine.wizarpos.mall.model.open.EditPasswordInput;
import cn.congine.wizarpos.mall.model.open.EditPasswordOutput;
import cn.congine.wizarpos.mall.model.open.ExchangeIntegralInput;
import cn.congine.wizarpos.mall.model.open.ExchangeIntegralOutput;
import cn.congine.wizarpos.mall.model.open.GetEmployeesOutput;
import cn.congine.wizarpos.mall.model.open.GetEmployeeslInput;
import cn.congine.wizarpos.mall.model.open.GetShopInfoInput;
import cn.congine.wizarpos.mall.model.open.GetShopInfoOutput;
import cn.congine.wizarpos.mall.model.open.LabelIdDto;
import cn.congine.wizarpos.mall.model.open.MemberPointsDetailInput;
import cn.congine.wizarpos.mall.model.open.MemberPointsDetailOutput;
import cn.congine.wizarpos.mall.model.open.MemberTicketDetailInput;
import cn.congine.wizarpos.mall.model.open.MemberTicketDetailOutput;
import cn.congine.wizarpos.mall.model.open.MerchantDef;
import cn.congine.wizarpos.mall.model.open.MerchantDefInfoOutput;
import cn.congine.wizarpos.mall.model.open.MerchantDefQueryInput;
import cn.congine.wizarpos.mall.model.open.MerchantDefQueryOutput;
import cn.congine.wizarpos.mall.model.open.MerchantDefVo;
import cn.congine.wizarpos.mall.model.open.PayTheBillInput;
import cn.congine.wizarpos.mall.model.open.PayTheBillOutput;
import cn.congine.wizarpos.mall.model.open.PointsTranLog;
import cn.congine.wizarpos.mall.model.open.ResetPasswordInput;
import cn.congine.wizarpos.mall.model.open.ResetPasswordOutput;
import cn.congine.wizarpos.mall.model.open.ShopAddressInput;
import cn.congine.wizarpos.mall.model.open.ShopAddressOutput;
import cn.congine.wizarpos.mall.model.open.ShopAddressPair;
import cn.congine.wizarpos.mall.model.open.ShopInfoPair;
import cn.congine.wizarpos.mall.model.open.ShopTranLogInput;
import cn.congine.wizarpos.mall.model.open.ShopTranLogOutput;
import cn.congine.wizarpos.mall.model.open.TicketAddDetailInput;
import cn.congine.wizarpos.mall.model.open.TicketAddDetailOutput;
import cn.congine.wizarpos.mall.model.open.TicketBindingInput;
import cn.congine.wizarpos.mall.model.open.TicketBindingOutput;
import cn.congine.wizarpos.mall.model.open.TicketInfoDetailInput;
import cn.congine.wizarpos.mall.model.open.TicketInfoDetailOutput;
import cn.congine.wizarpos.mall.model.open.TicketInfoListInput;
import cn.congine.wizarpos.mall.model.open.TicketInfoListOutput;
import cn.congine.wizarpos.mall.model.open.TicketInfoPayUse;
import cn.congine.wizarpos.mall.model.open.TicketInfoVo;
import cn.congine.wizarpos.mall.model.open.TicketListInput;
import cn.congine.wizarpos.mall.model.open.TicketListOutput;
import cn.congine.wizarpos.mall.model.open.TicketMarketDef;
import cn.congine.wizarpos.mall.model.open.TicketMarketDefInput;
import cn.congine.wizarpos.mall.model.open.TicketMarketDefListInput;
import cn.congine.wizarpos.mall.model.open.TicketMarketDefListOutput;
import cn.congine.wizarpos.mall.model.open.TicketMarketDefOutput;
import cn.congine.wizarpos.mall.model.open.TicketToPackageInput;
import cn.congine.wizarpos.mall.model.open.TicketToPackageOutput;
import cn.congine.wizarpos.mall.model.open.TicketTranLog;
import cn.congine.wizarpos.mall.model.open.TicketUseLog;
import cn.congine.wizarpos.mall.model.open.TicketUseLogInput;
import cn.congine.wizarpos.mall.model.open.TicketUseLogOutput;
import cn.congine.wizarpos.mall.model.open.TranLogView;
import cn.congine.wizarpos.mall.model.open.TranLogVo;
import cn.congine.wizarpos.mall.model.open.UpdateUserInfoInput;
import cn.congine.wizarpos.mall.model.open.UpdateUserInfoOutput;
import cn.congine.wizarpos.mall.model.open.WeChartMemberCardHolderInput;
import cn.congine.wizarpos.mall.model.open.WeChartMemberCardHolderOutput;
import cn.congine.wizarpos.mall.model.open.WeChartMemberInfoQueryInput;
import cn.congine.wizarpos.mall.model.open.WeChartMemberInfoQueryOutput;
import cn.congine.wizarpos.mall.model.open.WeChartMemberInfoQueryOutput.Result;
import cn.congine.wizarpos.mall.model.open.WeChartMemberRegisterCardInput;
import cn.congine.wizarpos.mall.model.open.WeChartMemberRegisterCardOutput;
import cn.congine.wizarpos.mall.service.impl.WPosHttpClient;
import cn.congine.wizarpos.mall.service.impl.WizarposOpenRestClient;
import cn.congine.wizarpos.mall.tenpay.util.MD5Util;
import cn.congine.wizarpos.mall.utils.MatrixToImageWriter;
import cn.congine.wizarpos.mall.utils.SysConstants;
import cn.congine.wizarpos.mall.utils.Utils;
import cn.congine.wizarpos.mall.utils.WxSignUtil;
import cn.congine.wizarpos.mall.vo.CateringReOrderView;
import cn.congine.wizarpos.mall.vo.Record;
import cn.congine.wizarpos.mall.vo.Ticket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;

@Controller
@RequestMapping(value = "/vip")
public class CardAction {
	private final Log log = LogFactory.getLog(getClass());

	@Autowired
	private WPosHttpClient wposHttpClient;

	@Resource(name = "messageSource")
	private MessageSource messageSource;

	@Autowired
	private WizarposOpenRestClient wizarposOpenRestClient;

	/**
	 * 会员卡展示页面
	 * 
	 * @param openId
	 * @param mid
	 * @return
	 */
	@RequestMapping(value = "/vip_card")
	public ModelAndView vipCard(
			@RequestParam(value = "mid", required = true) String mid,
			HttpServletRequest httpRequest) {
		String openId = (String) httpRequest.getSession().getAttribute("openId");
		if (StringUtils.isEmpty(openId)) {//session过期，跳转到登录注册页面
			return new ModelAndView("forward:login");
		}
		log.debug("vip_card--------------------");
		log.debug("openId =" + openId);
		log.debug("mid =" + mid);

		Map<String, Object> data = new HashMap<String, Object>();
		data.put("mid", mid);
		
		// 商户数据
		MerchantDefQueryInput merchantDefQueryInput = new MerchantDefQueryInput();
		merchantDefQueryInput.setMid(mid);
		MerchantDefInfoOutput merchantDefInfoOutput = (MerchantDefInfoOutput) wizarposOpenRestClient.post(merchantDefQueryInput, "/merchantdef/info/query", MerchantDefInfoOutput.class);
		if (merchantDefInfoOutput == null || !SysConstants.OPEN_SUCCESS.equals(merchantDefInfoOutput.getCode())) {
			data.put("error_msg", SysConstants.NO_MERCHANT);
			return new ModelAndView("card/error",data);
		} else {
			MerchantDefInfoOutput.Result result = merchantDefInfoOutput.getResult();
			MerchantDefVo merchantDef = result.getMerchantDef();
			if (StringUtils.isEmpty(merchantDef.getVipImage())) {
				merchantDef.setVipImage(SysConstants.DEFAULT_VIP_IMAGE);
			}
			JSONObject attachFields = (JSONObject) JSONObject.toJSON(result.getAttachFields());
			data.put("chargeOnline", attachFields.getString("chargeOnline"));
			data.put("onlinePay", attachFields.getString("onlinePay"));
			data.put("cardImage", merchantDef.getVipImage());
		}		
		
		// 用户数据
		WeChartMemberInfoQueryInput input = new WeChartMemberInfoQueryInput();
		input.setMid(mid);
		input.setOpenId(openId);
		WeChartMemberInfoQueryOutput output = (WeChartMemberInfoQueryOutput) wizarposOpenRestClient.post(input, "/wechart/info/query", WeChartMemberInfoQueryOutput.class);		
		if (output == null) {
			data.put("error_msg", SysConstants.SYSTEM_RRROR);
			return new ModelAndView("card/error",data);
		}
		if (!SysConstants.OPEN_SUCCESS.equals(output.getCode())) {
			if (SysConstants.NO_MERCHANT_CODE.equals(output.getCode())) {
				data.put("error_msg", SysConstants.NO_MERCHANT);
				return new ModelAndView("card/error",data);
			} else if ("60007".equals(output.getCode())){ // 会员卡不存在
				return new ModelAndView("forward:receiveCard");
			}
		} 
		
		Result memberInfo = output.getResult();
		if (memberInfo == null || !"false".equals(memberInfo.getCanceled()) || !"false".equals(memberInfo.getFreeze())) {
			data.put("error_msg", "会员卡已失效");
			return new ModelAndView("card/error",data);
		}
		
		// TODO 调用券列表接口 
		TicketInfoListInput ticketInfoListInput = new TicketInfoListInput();
		ticketInfoListInput.setMid(mid);
		ticketInfoListInput.setCardId(memberInfo.getId());
		TicketInfoListOutput ticketInfoListOutput = (TicketInfoListOutput) wizarposOpenRestClient.post(ticketInfoListInput, "/wechart/ticket_info_list", TicketInfoListOutput.class);
		int count = 0;
		int expire = 0;
		String mrtType = null;
		if (ticketInfoListOutput != null && "0".equals(ticketInfoListOutput.getCode())) {
			cn.congine.wizarpos.mall.model.open.TicketInfoListOutput.Result result = ticketInfoListOutput.getResult();
			if (result != null) {
				List<TicketInfoVo> ticketInstsToExpired = result.getTicketToExpiredList();
				List<TicketInfoVo> ticketInstsNormal = result.getTicketList();
				if (ticketInstsToExpired != null) {
					expire = ticketInstsToExpired.size();
				}
				if (ticketInstsNormal != null) {
					count = ticketInstsNormal.size();
				}
				count += expire;
				mrtType = result.getMerchantType();
			}
			data.put("logoImage", result.getLogoImage());
			data.put("marchantName", result.getMerchantName());
			
		} else {
			data.put("error_msg", "系统错误，请重试");
			return new ModelAndView("card/error", data);
		} 
		
		List<LabelIdDto> labelIds = memberInfo.getLabelIds();
		if (labelIds != null && !labelIds.isEmpty()) {
			data.put("level", labelIds.get(0).getValue());
		}
		
		data.put("mrtType", mrtType); // 券列表接口结果集获取
		data.put("balance", Utils.changF2Y(Integer.valueOf(memberInfo.getBalance())));
		data.put("cardNo", memberInfo.getCardNo());
		data.put("imgUrl", memberInfo.getImgUrl());
		data.put("nickName", StringUtils.isEmpty(memberInfo.getNickName()) ? memberInfo.getUserName() : memberInfo.getNickName());
		data.put("points", StringUtils.isEmpty(memberInfo.getPoints()) ? "0" : memberInfo.getPoints());
		data.put("count", count);
		data.put("expire", expire);
		
		return new ModelAndView("card/vip_card", data);
	}

	/**
	 * 用户信息修改页
	 * 
	 * @param mid
	 * @param httpRequest
	 * @return
	 */
	@RequestMapping(value = "/user_info")
	public ModelAndView userInfo(
			@RequestParam(value = "mid") String mid,
			HttpServletRequest httpRequest) {
		String openId = (String) httpRequest.getSession().getAttribute("openId");
		String cardId = (String) httpRequest.getSession().getAttribute("mrtCardId");
		if (StringUtils.isEmpty(openId) || StringUtils.isEmpty(cardId)) {//session过期，跳转到登录注册页面
			return new ModelAndView("forward:login");
		}
		Map<String, Object> data = new HashMap<String, Object>();
		// 用户数据
		WeChartMemberInfoQueryInput memberInfoQueryInput = new WeChartMemberInfoQueryInput();
		memberInfoQueryInput.setMid(mid);
		memberInfoQueryInput.setOpenId(openId);
		WeChartMemberInfoQueryOutput memberInfoQueryOutput = (WeChartMemberInfoQueryOutput) wizarposOpenRestClient.post(memberInfoQueryInput, "/wechart/info/query", WeChartMemberInfoQueryOutput.class);		
		if (memberInfoQueryOutput == null) {
			log.error("请求开放平台查询会员信息接口失败");
			data.put("err_message", "系统异常，请稍后重试");
			return new ModelAndView("card/error",data);
		} else if (SysConstants.OPEN_SUCCESS.equals(memberInfoQueryOutput.getCode())) {
			WeChartMemberInfoQueryOutput.Result memberInfo = memberInfoQueryOutput.getResult();
			data.put("memberInfo", memberInfo);
			
			data.put("name", memberInfo.getUserName());
			data.put("phone", memberInfo.getMobileNo());
			if ("U".equals(memberInfo.getSex())) {
				data.put("sex", "M");
			} else {
				data.put("sex", memberInfo.getSex());
			}
			
			if (StringUtils.isEmpty(memberInfo.getBirthday())) {
				data.put("birthday", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
			} else {
				data.put("birthday", memberInfo.getBirthday());
			}
			
			
		} else {
			log.error("code：" + memberInfoQueryOutput.getCode());
			log.error("message：" + memberInfoQueryOutput.getMessage());
			data.put("err_message", memberInfoQueryOutput.getMessage());
			return new ModelAndView("card/error",data);
		}

		AddressGainInput addressGainInput = new AddressGainInput();
		addressGainInput.setMid(mid);
		addressGainInput.setCardId(cardId);
		AddressGainOutput addressGainOutput = (AddressGainOutput) wizarposOpenRestClient.post(addressGainInput, "/address/gain", AddressGainOutput.class);		
		if (addressGainOutput != null || SysConstants.OPEN_SUCCESS.equals(addressGainOutput.getCode())) {
			List<Address> list = addressGainOutput.getResult();
			if (list != null && !list.isEmpty()) {
				Address address = null;
				// 优先取默认地址，若无默认地址，选择地址列表的第一个地址
				boolean defaultState = false;
				for (Address a : list) {
					// 是否为默认地址（1：默认地址，0：非默认地址）
					if ("1".equals(a.getDefaultState())) {
						defaultState = true;
						address = a;
						break;
					}
				}
				if (!defaultState) {
					address = list.get(0);
				}
				if (address != null) {
					String addr = address.getAddress();
					String[] addressArr = (addr != null) ? addr.split(" ") : new String[0];
					data.put("province", addressArr.length > 0 ? addressArr[0] : "");
					data.put("city", addressArr.length > 1 ? addressArr[1] : "");
					data.put("county", addressArr.length > 2 ? addressArr[2] : "");
					StringBuffer sb = new StringBuffer();
					for (int i=3; i < addressArr.length; i++) {
						sb.append(addressArr[i]);
						sb.append(" ");
					}
					data.put("address", sb.toString());		
					data.put("addressId", address.getId());
					data.put("defaultState", address.getDefaultState());
					data.put("zipCode", address.getZipCode());
				}
			}
		}
		
		data.put("mid", mid);
		return new ModelAndView("card/userinfo", data);
	}

	/**
	 * 去买单页面
	 * 
	 * @param mid
	 * @param httpRequest
	 * @return
	 */
	@RequestMapping(value = "/to_pay_the_bill")
	public ModelAndView toPayTheBill(
			@RequestParam(value = "mid") String mid,
			HttpServletRequest httpRequest) {
		String openId = (String) httpRequest.getSession().getAttribute("openId");
		String cardId = (String) httpRequest.getSession().getAttribute("mrtCardId");
		if (StringUtils.isEmpty(openId) || StringUtils.isEmpty(cardId)) {//session过期，跳转到登录注册页面
			return new ModelAndView("forward:login");
		}
		Map<String, Object> data = new HashMap<String, Object>();
		String isMainStore = "0";
		// 查询商户信息
		MerchantDefQueryInput merchantDefQueryInput = new MerchantDefQueryInput();
		merchantDefQueryInput.setMid(mid);
		MerchantDefQueryOutput merchantDefouptut = (MerchantDefQueryOutput) wizarposOpenRestClient.post(merchantDefQueryInput, "/merchantdef/info", MerchantDefQueryOutput.class);
		if (merchantDefouptut == null) {
			log.error("请求开放平台查询商户信息接口失败");
			log.error("mid="+mid);
			data.put("err_message", "系统错误");
			return new ModelAndView("error", data);
		} else if (SysConstants.OPEN_SUCCESS.equals(merchantDefouptut.getCode())) {
			MerchantDef merchantDef =  merchantDefouptut.getResult();
			isMainStore = merchantDef.getIsVirtualMainStore();
			data.put("merchant", merchantDef);
			data.put("mid", mid);
		} else {
			log.error("code：" + merchantDefouptut.getCode());
			log.error("message：" + merchantDefouptut.getMessage());
			log.error("mid="+mid);
			data.put("err_message", "系统异常");
			return new ModelAndView("error", data);
		}
		
		// 获取商家信息
		GetShopInfoInput getShopInfoInput = new GetShopInfoInput();
		getShopInfoInput.setMid(mid);
		getShopInfoInput.setType("1"); // 0 买单
		GetShopInfoOutput getShopInfoOutput = (GetShopInfoOutput) wizarposOpenRestClient.post(getShopInfoInput, "/dzx/getShopInfo", GetShopInfoOutput.class);								
		if (getShopInfoOutput == null) {
			log.error("请求开放平台获取商户信息（fid下mid集合）或门店信息（mid下sn集合）接口失败");
			log.error("mid："+mid);
			return new ModelAndView("error").addObject("err_message", SysConstants.OPEN_ERROR_MESSAGE);			
		} else if (!SysConstants.OPEN_SUCCESS.equals(getShopInfoOutput.getCode())) {
			log.error("code：" + getShopInfoOutput.getCode());
			log.error("message：" + getShopInfoOutput.getMessage());
			return new ModelAndView("error").addObject("err_message", getShopInfoOutput.getMessage());	
		}
		List<ShopInfoPair> shopInfoPairs = getShopInfoOutput.getResult().getShopInfoPairs();
		data.put("shopInfoPairs", shopInfoPairs);
		
		// 用户数据
		WeChartMemberInfoQueryInput memberInfoQueryInput = new WeChartMemberInfoQueryInput();
		memberInfoQueryInput.setMid(mid);
		memberInfoQueryInput.setOpenId(openId);
		WeChartMemberInfoQueryOutput memberInfoQueryOutput = (WeChartMemberInfoQueryOutput) wizarposOpenRestClient.post(memberInfoQueryInput, "/wechart/info/query", WeChartMemberInfoQueryOutput.class);		
		if (memberInfoQueryOutput == null) {
			log.error("请求开放平台查询会员信息接口失败");
			data.put("err_message", "系统异常，请稍后重试");
			return new ModelAndView("card/error",data);
		} else if (SysConstants.OPEN_SUCCESS.equals(memberInfoQueryOutput.getCode())) {
			WeChartMemberInfoQueryOutput.Result memberInfo = memberInfoQueryOutput.getResult();
		} else {
			log.error("code：" + memberInfoQueryOutput.getCode());
			log.error("message：" + memberInfoQueryOutput.getMessage());
			data.put("err_message", memberInfoQueryOutput.getMessage());
			return new ModelAndView("card/error",data);
		}
		List<TicketInfoPayUse> tickets = wposHttpClient.getPayUseTickets(mid, cardId);
		if (tickets != null) {
			data.put("ticketNum", tickets.size());
		} else {
			data.put("ticketNum", 0);
		}
		data.put("cashList", tickets);
		
		// 获取员工编号信息（东志信用）
		GetEmployeeslInput getEmployeeslInput = new GetEmployeeslInput();
		getEmployeeslInput.setMid(mid);
		GetEmployeesOutput getEmployeesOutput = (GetEmployeesOutput) wizarposOpenRestClient.post(getEmployeeslInput, "/dzx/get/employees", GetEmployeesOutput.class);
		if (getEmployeesOutput == null) {
			log.error("请求开放平台获取员工编号信息接口失败");
			log.error("mid="+mid);
			data.put("err_message", "系统错误");
			return new ModelAndView("error", data);
		} else if (SysConstants.OPEN_SUCCESS.equals(getEmployeesOutput.getCode())) {
			data.put("employeePairs", getEmployeesOutput.getResult().getEmployeePairs());
		} else {
			log.error("code：" + getEmployeesOutput.getCode());
			log.error("message：" + getEmployeesOutput.getMessage());
			log.error("mid="+mid);
			data.put("err_message", "系统异常");
			return new ModelAndView("error", data);
		}
		
		return new ModelAndView("card/pay_the_bill",data);
	}
	
	/**
	 * 用户信息修改页
	 * 
	 * @param mid
	 * @param httpRequest
	 * @return
	 */
	@RequestMapping(value = "/to_edit_psw")
	public ModelAndView toEditPsw(
			@RequestParam(value = "mid") String mid,
			HttpServletRequest httpRequest) {
		String openId = (String) httpRequest.getSession().getAttribute("openId");
		String cardId = (String) httpRequest.getSession().getAttribute("mrtCardId");
		if (StringUtils.isEmpty(openId) || StringUtils.isEmpty(cardId)) {//session过期，跳转到登录注册页面
			return new ModelAndView("forward:login");
		}
		Map<String, Object> data = new HashMap<String, Object>();
		data.put("mid", mid);
		String smsChannelId = null;
		String mobileNo = null;
		MerchantDefQueryInput merchantDefQueryInput = new MerchantDefQueryInput();
		merchantDefQueryInput.setMid(mid);
		MerchantDefInfoOutput merchantDefInfoOutput = (MerchantDefInfoOutput) wizarposOpenRestClient.post(merchantDefQueryInput, "/merchantdef/info/query", MerchantDefInfoOutput.class);
		if (merchantDefInfoOutput != null && SysConstants.OPEN_SUCCESS.equals(merchantDefInfoOutput.getCode())) {
			MerchantDefInfoOutput.Result result = merchantDefInfoOutput.getResult();
			if (result != null ) {
				JSONObject attachFields = (JSONObject) JSONObject.toJSON(result.getAttachFields());
				smsChannelId = attachFields.getString("smsChannelId");
			}
		}
		// 用户数据
		WeChartMemberInfoQueryInput memberInfoQueryInput = new WeChartMemberInfoQueryInput();
		memberInfoQueryInput.setMid(mid);
		memberInfoQueryInput.setOpenId(openId);
		WeChartMemberInfoQueryOutput memberInfoQueryOutput = (WeChartMemberInfoQueryOutput) wizarposOpenRestClient.post(memberInfoQueryInput, "/wechart/info/query", WeChartMemberInfoQueryOutput.class);		
		if (memberInfoQueryOutput == null) {
			log.error("请求开放平台查询会员信息接口失败");
			data.put("err_message", "系统异常，请稍后重试");
			return new ModelAndView("card/error",data);
		} else if (SysConstants.OPEN_SUCCESS.equals(memberInfoQueryOutput.getCode())) {
			WeChartMemberInfoQueryOutput.Result memberInfo = memberInfoQueryOutput.getResult();
			mobileNo = memberInfo.getMobileNo();
		} else {
			log.error("code：" + memberInfoQueryOutput.getCode());
			log.error("message：" + memberInfoQueryOutput.getMessage());
			data.put("err_message", memberInfoQueryOutput.getMessage());
			return new ModelAndView("card/error",data);
		}
		// 商户未开通短息渠道或者用户手机号为空 则不使用短信验证码修改密码
		if (StringUtils.isEmpty(smsChannelId) || StringUtils.isEmpty(mobileNo)) {
			return new ModelAndView("card/editpsw", data);
		} else {
			data.put("mobileNo", mobileNo);
			return new ModelAndView("card/editpsw_vcode", data);
		}
	}
	
	/**
	 * 修改用户信息
	 * 
	 * @param mid
	 * @param httpRequest
	 * @return
	 */
	@RequestMapping(value = "/update_user_info")
	@ResponseBody
	public RespMessage updateUserInfo(
			@RequestParam(value = "mid") String mid,
			@RequestParam(value = "addressId", required = false) String addressId,
			@RequestParam(value = "userName", required = true) String userName,
			@RequestParam(value = "mPhone", required = true) String mPhone,
			@RequestParam(value = "sex" , required = false) String sex,
			@RequestParam(value = "birthday" , required = true) String birthday,
			@RequestParam(value = "address" , required = false) String address,
			@RequestParam(value = "defaultState" , required = false) String defaultState,
			@RequestParam(value = "zipCode" , required = false) String zipCode,
			HttpServletRequest httpRequest) {
		RespMessage res = new RespMessage();
		String cardId = (String) httpRequest.getSession().getAttribute("mrtCardId");
		if (StringUtils.isEmpty(cardId)) {//session过期，跳转到登录注册页面
			res.setCode(2);
			return res;
		}
		Map<String, Object> data = new HashMap<String, Object>();
		// 请求开放平台更新用户信息
		UpdateUserInfoInput updateUserInfoInput = new UpdateUserInfoInput();
		updateUserInfoInput.setMid(mid);
		updateUserInfoInput.setCardId(cardId);
		updateUserInfoInput.setUserName(userName);
		updateUserInfoInput.setSex(sex);
		updateUserInfoInput.setMobileNo(mPhone);
		updateUserInfoInput.setBirthday(birthday);
		UpdateUserInfoOutput updateUserInfoOutput = (UpdateUserInfoOutput) wizarposOpenRestClient.post(updateUserInfoInput, "/wechart/update/userinfo", UpdateUserInfoOutput.class);		
		if (updateUserInfoOutput == null) {
			log.error("请求开放平台更新用户信息接口失败");
			data.put("err_message", "系统异常，请稍后重试");
			res.setCode(1);
			res.setMessage("系统异常，请稍后重试");
			return res;
		} else if (!SysConstants.OPEN_SUCCESS.equals(updateUserInfoOutput.getCode())) {
			log.error("code：" + updateUserInfoOutput.getCode());
			log.error("message：" + updateUserInfoOutput.getMessage());
			res.setCode(1);
			res.setMessage("操作失败：" + updateUserInfoOutput.getMessage());
			return res;
		}
		
		// 地址未填写
		if (StringUtils.isEmpty(address)) {
			return res;
		}
		// 修改地址
		AddressEditInput addressEditInput = new AddressEditInput();
		addressEditInput.setMid(mid);
		addressEditInput.setCardId(cardId);
		addressEditInput.setAddress(address);
		addressEditInput.setPhone(mPhone);
		addressEditInput.setUserName(userName);
		addressEditInput.setZipCode(zipCode);
		
		if (StringUtils.isEmpty(addressId)) {
			addressEditInput.setOperateType("I");
		} else {
			addressEditInput.setOperateType("U");
			addressEditInput.setId(addressId);
		}
		if ("1".equals(defaultState)) {
			addressEditInput.setDefaultState("1");
		} else {
			addressEditInput.setDefaultState("0");
		}		
		AddressEditOutput addressEditOutput = (AddressEditOutput) wizarposOpenRestClient.post(addressEditInput, "/address/edit", AddressEditOutput.class);		
		if (addressEditOutput == null) {
			log.error("请求开放平台修改地址接口失败");
			data.put("err_message", "系统异常，请稍后重试");
			res.setCode(1);
			res.setMessage("系统异常，请稍后重试");
			return res;
		} else if (!SysConstants.OPEN_SUCCESS.equals(addressEditOutput.getCode())) {
			log.error("code：" + addressEditOutput.getCode());
			log.error("message：" + addressEditOutput.getMessage());
			res.setCode(1);
			res.setMessage("操作失败：" + addressEditOutput.getMessage());
			return res;
		}		

		return res;
	}

	/**
	 * 修改交易密码
	 * 
	 * @param mid
	 * @param httpRequest
	 * @return
	 */
	@RequestMapping(value = "/edit_psw")
	@ResponseBody
	public RespMessage editPsw(
			@RequestParam(value = "mid") String mid,
			@RequestParam(value = "oldPassword", required = true) String oldPassword,
			@RequestParam(value = "newPassword", required = true) String newPassword,
			@RequestParam(value = "confirmPassword", required = true) String confirmPassword,
			HttpServletRequest httpRequest) {
		RespMessage res = new RespMessage();
		String cardId = (String) httpRequest.getSession().getAttribute("mrtCardId");
		if (StringUtils.isEmpty(cardId)) {//session过期，跳转到登录注册页面
			res.setCode(2);
			return res;
		}
		// 请求开放平台更新用户信息
		EditPasswordInput editPasswordInput = new EditPasswordInput();
		editPasswordInput.setMid(mid);
		editPasswordInput.setCardId(cardId);
		editPasswordInput.setOldPassword(MD5Util.MD5Encode(oldPassword, "UTF-8")); // 普通md5加密，6-8位数字组成)
		editPasswordInput.setNewPassword(MD5Util.MD5Encode(newPassword, "UTF-8")); // 普通md5加密，6-8位数字组成)
		editPasswordInput.setConfirmPassword(MD5Util.MD5Encode(confirmPassword, "UTF-8")); // 普通md5加密，6-8位数字组成)
		EditPasswordOutput editPasswordOutput = (EditPasswordOutput) wizarposOpenRestClient.post(editPasswordInput, "/wechart/edit/psw", EditPasswordOutput.class);		
		if (editPasswordOutput == null) {
			log.error("请求开放平台修改密码接口失败");
			res.setCode(1);
			res.setMessage("系统异常，请稍后重试");
			return res;
		} else if (SysConstants.OPEN_SUCCESS.equals(editPasswordOutput.getCode())) {
			
		} else {
			log.error("code：" + editPasswordOutput.getCode());
			log.error("message：" + editPasswordOutput.getMessage());
			if ("60072".equals(editPasswordOutput.getCode())) {
				res.setMessage("操作失败：旧密码错误");
			} else if ("60100".equals(editPasswordOutput.getCode())) {
				res.setMessage("操作失败：新密码和确认密码不一致");
			} else {
				res.setMessage("操作失败：" + editPasswordOutput.getMessage());
			}
			res.setCode(1);
			return res;
		}
	

		return res;
	}

	/**
	 * 通过短信验证码重置交易密码
	 * 
	 * @param mid
	 * @param password
	 * @param httpRequest
	 * @return
	 */
	@RequestMapping(value = "/reset_psw")
	@ResponseBody
	public RespMessage resetPsw(
			@RequestParam(value = "mid") String mid,
			@RequestParam(value = "password", required = true) String password,
			HttpServletRequest httpRequest) {
		RespMessage res = new RespMessage();
		String cardId = (String) httpRequest.getSession().getAttribute("mrtCardId");
		if (StringUtils.isEmpty(cardId)) {//session过期，跳转到登录注册页面
			res.setCode(2);
			return res;
		}
		// 请求开放平台短信验证码重置密码接口
		ResetPasswordInput resetPasswordInput = new ResetPasswordInput();
		resetPasswordInput.setMid(mid);
		resetPasswordInput.setCardId(cardId);
		resetPasswordInput.setPassword(MD5Util.MD5Encode(password, "UTF-8")); // 普通md5加密，6-8位数字组成
		ResetPasswordOutput resetPasswordOutput = (ResetPasswordOutput) wizarposOpenRestClient.post(resetPasswordInput, "/wechart/reset/psw", ResetPasswordOutput.class);		
		if (resetPasswordOutput == null) {
			log.error("请求开放平台短信验证码重置密码接口失败");
			res.setCode(1);
			res.setMessage("系统异常，请稍后重试");
			return res;
		} else if (SysConstants.OPEN_SUCCESS.equals(resetPasswordOutput.getCode())) {
			
		} else {
			log.error("code：" + resetPasswordOutput.getCode());
			log.error("message：" + resetPasswordOutput.getMessage());
			res.setMessage("修改交易密码失败");
			res.setCode(1);
			return res;
		}

		return res;
	}

	/**
	 * 会员卡激活（更新会员信息）
	 * 
	 * @param mid
	 * @param name
	 * @param phone
	 * @param psw
	 * @param birthday
	 * @param httpRequest
	 * @return
	 */
	@RequestMapping(value = "/activate_card")
	@ResponseBody
	public RespMessage activateCard(
			@RequestParam(value = "mid") String mid,
			@RequestParam(value = "name", required = true) String name,
			@RequestParam(value = "phone", required = true) String phone,
			@RequestParam(value = "psw" , required = false) String psw,
			@RequestParam(value = "birthday" , required = true) String birthday,
			HttpServletRequest httpRequest) {
		RespMessage res = new RespMessage();
		String cardId = (String) httpRequest.getSession().getAttribute("mrtCardId");
		if (StringUtils.isEmpty(cardId)) {//session过期，跳转到登录注册页面
			res.setCode(2);
			return res;
		}
		Map<String, Object> data = new HashMap<String, Object>();
		log.debug("activate_card--------------------");
		log.debug("mid =" + mid);
		log.debug("cardId =" + cardId);
		
		// 请求开放平台更新用户信息
		UpdateUserInfoInput updateUserInfoInput = new UpdateUserInfoInput();
		updateUserInfoInput.setMid(mid);
		updateUserInfoInput.setCardId(cardId);
		updateUserInfoInput.setUserName(name);
		updateUserInfoInput.setMobileNo(phone);
		updateUserInfoInput.setBirthday(birthday);
		updateUserInfoInput.setPassword(MD5Util.MD5Encode(psw, "UTF-8")); // 普通md5加密，6-8位数字组成
		UpdateUserInfoOutput updateUserInfoOutput = (UpdateUserInfoOutput) wizarposOpenRestClient.post(updateUserInfoInput, "/wechart/update/userinfo", UpdateUserInfoOutput.class);		
		if (updateUserInfoOutput == null) {
			log.error("请求开放平台更新用户信息接口失败");
			data.put("err_message", "系统异常，请稍后重试");
			res.setCode(1);
			res.setMessage("系统异常，请稍后重试");
			return res;
		} else if (SysConstants.OPEN_SUCCESS.equals(updateUserInfoOutput.getCode())) {
			return res;
		} else {
			log.error("code：" + updateUserInfoOutput.getCode());
			log.error("message：" + updateUserInfoOutput.getMessage());
			res.setCode(1);
			res.setMessage("操作失败：" + updateUserInfoOutput.getMessage());
			return res;			
		}
	}
	
	/**
	 * 会员卡注册、激活信息录入页面
	 * 
	 * @param openId
	 * @param mid
	 * @return
	 */
	@RequestMapping(value = "/input_card")
	public ModelAndView inputCard(
			@RequestParam(value = "mid", required = true) String mid,
			RedirectAttributes attributes, HttpServletRequest httpRequest) {
		String openId = (String) httpRequest.getSession().getAttribute("openId");
		
		if (StringUtils.isEmpty(openId)) {//session过期，跳转到登录注册页面
			return new ModelAndView("forward:login");	
		}
		log.debug("input_card--------------------");
		log.debug("openId =" + openId);
		log.debug("mid =" + mid);
		Map<String, Object> data = new HashMap<String, Object>();
		JSONObject attachFields = null;
		boolean useVcode = false;
		// 查询商户信息
		MerchantDefQueryInput merchantDefQueryInput = new MerchantDefQueryInput();
		merchantDefQueryInput.setMid(mid);
		MerchantDefInfoOutput merchantDefOuptut = (MerchantDefInfoOutput) wizarposOpenRestClient.post(merchantDefQueryInput, "/merchantdef/info/query", MerchantDefInfoOutput.class);
		if (merchantDefOuptut == null) {
			log.error("请求开放平台查询商户信息接口失败");
			log.error("mid="+mid);
			data.put("err_message", "系统错误");
			return new ModelAndView("error", data);
		} else if (SysConstants.OPEN_SUCCESS.equals(merchantDefOuptut.getCode())) {
			attachFields = (JSONObject) JSONObject.toJSON(merchantDefOuptut.getResult().getAttachFields());
			if (!StringUtils.isEmpty(attachFields.getString("smsChannelId"))) { // 启用短信验证
				useVcode = true;
			}
		} else {
			log.error("code：" + merchantDefOuptut.getCode());
			log.error("message：" + merchantDefOuptut.getMessage());
			log.error("mid="+mid);
			data.put("err_message", "系统异常");
			return new ModelAndView("error", data);
		}
		
		data.put("openId", openId);
		data.put("mid", mid);
		data.put("birthday", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
		
		// 用户数据
		WeChartMemberInfoQueryInput memberInfoQueryInput = new WeChartMemberInfoQueryInput();
		memberInfoQueryInput.setMid(mid);
		memberInfoQueryInput.setOpenId(openId);
		WeChartMemberInfoQueryOutput memberInfoQueryOutput = (WeChartMemberInfoQueryOutput) wizarposOpenRestClient.post(memberInfoQueryInput, "/wechart/info/query", WeChartMemberInfoQueryOutput.class);		
		if (memberInfoQueryOutput == null) {
			log.error("请求开放平台查询会员信息接口失败");
			data.put("err_message", "系统异常，请稍后重试");
			return new ModelAndView("card/error",data);
		} else if (SysConstants.OPEN_SUCCESS.equals(memberInfoQueryOutput.getCode())) {
			WeChartMemberInfoQueryOutput.Result memberInfo = memberInfoQueryOutput.getResult();
			 // 会员卡存在未激活，用户名和手机号有空值，激活会员卡
			if (StringUtils.isEmpty(memberInfo.getUserName()) || StringUtils.isEmpty(memberInfo.getMobileNo())) {
				data.put("activateCard", "1");
				data.put("userName", memberInfo.getUserName());
				data.put("mobileNo", memberInfo.getMobileNo());
				data.put("birthday", memberInfo.getBirthday());
				if (useVcode) { // 启用短信验证
					return new ModelAndView("card/input_card_vcode", data);
				}
				return new ModelAndView("card/input_card", data);// 不启用短信验证
			} else {
				return new ModelAndView("forward:/vip/vip_card");
			}
		} else if ("60007".equals(memberInfoQueryOutput.getCode())) { // 会员卡不存在，领取会员卡
			data.put("activateCard", "0");
			if (useVcode) { // 启用短信验证
				return new ModelAndView("card/input_card_vcode", data);
			}
			return new ModelAndView("card/input_card", data);// 不启用短信验证
		} else {
			log.error("code：" + memberInfoQueryOutput.getCode());
			log.error("message：" + memberInfoQueryOutput.getMessage());
			data.put("err_message", memberInfoQueryOutput.getMessage());
			return new ModelAndView("card/error",data);
		}
	}

	/**
	 * 保存会员卡注册信息
	 * 
	 * @param openId
	 * @param mid
	 * @param name
	 * @param phone
	 * @return
	 */
	@RequestMapping(value = "/create_card")
	@ResponseBody
	public RespMessage createCard(
			@RequestParam(value = "mid", required = true) String mid,
			@RequestParam(value = "name", required = false) String name,
			@RequestParam(value = "phone", required = false) String phone,
			@RequestParam(value = "psw", required = false) String psw,
			@RequestParam(value = "birthday", required = false) String birthday,
			HttpServletRequest httpRequest) {
		RespMessage res = new RespMessage();
		String openId = (String) httpRequest.getSession().getAttribute("openId");
		if (StringUtils.isEmpty(openId)) {//session过期，跳转到登录注册页面
			res.setCode(2);
			return res;	
		}
		// 请求开放平台注册会员卡
		WeChartMemberRegisterCardInput input = new WeChartMemberRegisterCardInput();	
		input.setMid(mid);
		input.setOpenId(openId);
		input.setUserName(name);
		input.setMobileNo(phone);
		input.setBirthday(birthday);
		input.setPassword(MD5Util.MD5Encode(psw, "UTF-8")); // 普通md5加密，6-8位数字组成
		WeChartMemberRegisterCardOutput output = (WeChartMemberRegisterCardOutput) wizarposOpenRestClient.post(input, "/wechart/registerCard", WeChartMemberRegisterCardOutput.class);
		if (output == null) {
			log.error("请求开放平台注册会员卡接口失败");
			res.setMessage("系统错误、注册会员卡失败");
		} else if (SysConstants.OPEN_SUCCESS.equals(output.getCode())) {
			// 设置用户会员卡信息相关session数据
			WeChartMemberRegisterCardOutput.Result result = output.getResult();
			httpRequest.getSession().setAttribute("openId", openId);
			httpRequest.getSession().setAttribute("mid", mid);
			httpRequest.getSession().setAttribute("mrtCardNo", result.getCardNo());
			httpRequest.getSession().setAttribute("mrtCardId", result.getCardId());
			res.setCode(0);
			return res;
		} else {
			log.error("code：" + output.getCode());
			log.error("message：" + output.getMessage());
			res.setMessage(output.getMessage());
		}
		
		res.setCode(1);
		return res;	
	}
	
	@RequestMapping("/vipCardView")
	public ModelAndView vipCard() {
		return new ModelAndView("card/vip_card");
	}
	
	@RequestMapping("/inputCardView")
	public ModelAndView inputCardView() {
		return new ModelAndView("card/input_card");
	}

	/**
	 * 跳转到会员卡领取页面
	 * @param mid
	 * @param openId
	 * @return
	 * @author xudongdong
	 */
	@RequestMapping("/receiveCard")
	public ModelAndView receiveCard(
			@RequestParam(value = "mid", required = true) String mid,
			HttpServletRequest httpRequest) {
		String openId = (String) httpRequest.getSession().getAttribute("openId");
		if (StringUtils.isEmpty(openId)) {//session过期，跳转到登录注册页面
			return new ModelAndView("forward:login");
		}
		Map<String, Object> data = new HashMap<String, Object>();
		// 查询商户信息
		MerchantDefQueryInput merchantDefQueryInput = new MerchantDefQueryInput();
		merchantDefQueryInput.setMid(mid);
		MerchantDefQueryOutput merchantDefOuptut = (MerchantDefQueryOutput) wizarposOpenRestClient.post(merchantDefQueryInput, "/merchantdef/info", MerchantDefQueryOutput.class);
		if (merchantDefOuptut == null) {
			log.error("请求开放平台查询商户信息接口失败");
			log.error("mid="+mid);
			data.put("err_message", "系统错误");
			return new ModelAndView("error", data);
		} else if (SysConstants.OPEN_SUCCESS.equals(merchantDefOuptut.getCode())) {
			MerchantDef merchantDef = merchantDefOuptut.getResult();
			if (StringUtils.isEmpty(merchantDef.getVipImage())) {
				merchantDef.setVipImage(SysConstants.DEFAULT_VIP_IMAGE);
			}
			data.put("merchantDef", merchantDef);
		} else {
			log.error("code：" + merchantDefOuptut.getCode());
			log.error("message：" + merchantDefOuptut.getMessage());
			log.error("mid="+mid);
			data.put("err_message", "系统异常");
			return new ModelAndView("error", data);
		}	

		// 用户数据
		WeChartMemberInfoQueryInput memberInfoQueryInput = new WeChartMemberInfoQueryInput();
		memberInfoQueryInput.setMid(mid);
		memberInfoQueryInput.setOpenId(openId);
		WeChartMemberInfoQueryOutput memberInfoQueryOutput = (WeChartMemberInfoQueryOutput) wizarposOpenRestClient.post(memberInfoQueryInput, "/wechart/info/query", WeChartMemberInfoQueryOutput.class);		
		if (memberInfoQueryOutput == null) {
			log.error("请求开放平台查询会员信息接口失败");
			data.put("err_message", "系统异常，请稍后重试");
			return new ModelAndView("card/error",data);
		} else if (SysConstants.OPEN_SUCCESS.equals(memberInfoQueryOutput.getCode())) {
			WeChartMemberInfoQueryOutput.Result memberInfo = memberInfoQueryOutput.getResult();
			 // 会员卡存在未激活，用户名和手机号有空值，激活会员卡
			if (StringUtils.isEmpty(memberInfo.getUserName()) || StringUtils.isEmpty(memberInfo.getMobileNo())) {
				data.put("activateCard", "1");
			}
		} else if ("60007".equals(memberInfoQueryOutput.getCode())) { // 会员卡不存在，领取会员卡
			data.put("activateCard", "0");
		} else {
			log.error("code：" + memberInfoQueryOutput.getCode());
			log.error("message：" + memberInfoQueryOutput.getMessage());
			data.put("err_message", memberInfoQueryOutput.getMessage());
			return new ModelAndView("card/error",data);
		}
		
		data.put("mid", mid);	
		return new ModelAndView("card/receive_card", data);
	}
	
	/**
	 * 跳转到登录页
	 * @param mid
	 * @return
	 */
	@RequestMapping("/login")
	public ModelAndView login(
			@RequestParam(value = "mid", required = true) String mid,
			HttpServletRequest httpRequest) {
		// 商户数据
		MerchantDefQueryInput input = new MerchantDefQueryInput();
		input.setMid(mid);
		MerchantDefQueryOutput output = (MerchantDefQueryOutput) wizarposOpenRestClient.post(input, "/merchantdef/info", MerchantDefQueryOutput.class);		
		
		if(output == null || !SysConstants.OPEN_SUCCESS.equals(output.getCode()) || output.getResult() == null && output.getResult().getWeixinAppId() == null) {
			return new ModelAndView("error").addObject("err_message", "系统错误");
		} 
		
		MerchantDef merchant = output.getResult();
		if (merchant != null && merchant.getWeixinAppId() != null) {
			String dns = messageSource.getMessage(SysConstants.SERVICE_DNS, null, Locale.ENGLISH);
			String path = httpRequest.getContextPath();
			path = path.replace("/", "");
			return new ModelAndView("card/login").addObject("mid", mid).addObject("dns", dns).addObject("appid", merchant.getWeixinAppId()).addObject("contextPath", path);
		} else {
			return new ModelAndView("error").addObject("err_message", "商户信息异常");
		}
			
	}

	/**
	 * 查询电子券
	 * 
	 * @param openId
	 * @param mid
	 * @return
	 */
	private Map<String, Object> queryTicketForCard(String mid, String openId, String cardId) {
		log.debug("queryTicket--------------------");
		List<Ticket> list = new ArrayList<Ticket>();
		Map<String, Object> resMap = new HashMap<String, Object>();
		int count = 0;
		try {
			JSONObject result = wposHttpClient.getMemberTicketInfo(openId, mid, cardId);
			int code = result.getIntValue("code");
			log.debug("code =" + code);
			log.debug("msg =" + result.getString("msg"));

			if (code == SysConstants.SUCCESS) {
				count = (int) result.getJSONObject("result").get("counts");
				JSONArray tickes = (JSONArray) result.getJSONObject("result")
						.get("tickets");
				log.debug(tickes.toJSONString());
				for (int i = 0; i < tickes.size(); i++) {
					JSONObject tick = (JSONObject) tickes.get(i);
					if (tick.isEmpty()) {
						continue;
					}
					Ticket ti = new Ticket(i);
					ti.setTicketName(tick.getString("ticket_name"));
					ti.setCounts(tick.getString("num"));
					ti.setBalance(tick.containsKey("balance")? tick.getString("balance") : "0");
					ti.setDesc(tick.getString("descn"));
					ti.setExpriyTime(tick.getString("expriy"));
					// 1 为微信券，要求微信券的card_id存在
					if ("1".equals(tick.getString("wxFlag")) && tick.containsKey("wx_code_id")) {
						ti.setWxFlag("1");
						ti.setWxCodeId(tick.getString("wx_code_id"));
					}
					
					List<String> tmpNoList = tick.containsKey("ticketNo") ? Arrays
							.asList(tick.getString("ticketNo").split(","))
							: new ArrayList<String>();
					List<String> tmpAddedList = tick.containsKey("wxAdded") ? Arrays
							.asList(tick.getString("wxAdded").split(","))
							: new ArrayList<String>();
							
					String added = "1";
					String ticketNo = null;
					for (int j = 0; j < tmpAddedList.size(); j++) {
						String addedTmp = tmpAddedList.get(j);
						if (addedTmp == null || addedTmp.equals("0")) {
							added = "0";
							ticketNo = tmpNoList.get(j);
							break;
						}
					}
					ti.setWxAdded(added);
					ti.setTicketNo(ticketNo);
					
					list.add(ti);
				}

				log.debug(list.size());
				resMap.put("ticketCounts", count);
				resMap.put("ticket_list", list);
			} else {
				resMap.put("ticketCounts", count);
				resMap.put("ticket_list", list);
				log.error(result.getString("msg"));
			}
		} catch (Exception e) {
			log.error(e);
		}
		return resMap;
	}

	/**
	 * 查询余额
	 * 
	 * @param openId
	 * @param mid
	 * @return
	 */
	@RequestMapping(value = "/query_balance")
	public ModelAndView queryBalance(
			@RequestParam(value = "mid", required = true) String mid,
			HttpServletRequest httpRequest) {
		String openId = (String) httpRequest.getSession().getAttribute("openId");
		if (StringUtils.isEmpty(openId)) {//session过期，跳转到登录注册页面
			return new ModelAndView("forward:login");
		}
		log.debug("query_balance--------------------");
		log.debug("openId =" + openId);
		log.debug("mid =" + mid);

		Map<String, Object> data = new HashMap<String, Object>();
		data.put("mid", mid);
		data.put("error_msg", "");
		try {
			// 请求开放平台查询会员卡信息
			WeChartMemberInfoQueryInput input = new WeChartMemberInfoQueryInput();
			input.setMid(mid);
			input.setOpenId(openId);
			WeChartMemberInfoQueryOutput output = (WeChartMemberInfoQueryOutput) wizarposOpenRestClient.post(input, "/wechart/info/query", WeChartMemberInfoQueryOutput.class);
			if (output != null && "0".equals(output.getCode())) {
				if (output.getResult() != null) {
					cn.congine.wizarpos.mall.model.open.WeChartMemberInfoQueryOutput.Result result = output.getResult();
					data.put("card_no", result.getCardNo());
					data.put("balance", Utils.changF2Y(Integer.valueOf(result.getBalance())));
					return new ModelAndView("card/card_balance", data);
				} else {
					data.put("error_msg", "系统异常，请重试");// 其他错误，系统异常
				}
			} else if (output == null) {// 请求开放平台失败
				data.put("error_msg", "系统异常，请重试");// 其他错误，系统异常
			} else if ("60001".equals(output.getCode())) {// 60001 	非法慧商户号
				data.put("error_msg", output.getMessage());// 未知商户
			} else if ("60007".equals(output.getCode())) {// 60007	会员不存在
				//若无会员卡，则前往会员卡领取页面领取会员卡
				return new ModelAndView("forward:receiveCard?mid"+mid);
			} else {
				// 60002	在此商户下不存在此会员
				// 60009	入参为空
				log.error("code: " + output.getCode());
				log.error("message: " + output.getMessage());
				data.put("error_msg", "系统异常，请重试");// 其他错误，系统异常
			}

		} catch (Exception e) {
			log.error(e);
			data.put("error_msg", e.getMessage());
		}
		return new ModelAndView("card/error", data);
	}

	/**
	 * 查询积分
	 * 
	 * @param openId
	 * @param mid
	 * @return
	 */

	@RequestMapping(value = "/query_integral")
	public ModelAndView queryIntegral(
			@RequestParam(value = "mid", required = true) String mid,
			HttpServletRequest httpRequest) {
		String openId = (String) httpRequest.getSession().getAttribute("openId");
		if (StringUtils.isEmpty(openId)) {//session过期，跳转到登录注册页面
			return new ModelAndView("forward:login");
		}
		log.debug("query_integral--------------------");
		log.debug("openId =" + openId);
		log.debug("mid =" + mid);
		Map<String, Object> data = new HashMap<String, Object>();
		data.put("openId", openId);
		data.put("mid", mid);
		// 用户数据
		WeChartMemberInfoQueryInput memberInfoQueryInput = new WeChartMemberInfoQueryInput();
		memberInfoQueryInput.setMid(mid);
		memberInfoQueryInput.setOpenId(openId);
		WeChartMemberInfoQueryOutput memberInfoQueryOutput = (WeChartMemberInfoQueryOutput) wizarposOpenRestClient.post(memberInfoQueryInput, "/wechart/info/query", WeChartMemberInfoQueryOutput.class);		
		if (memberInfoQueryOutput == null) {
			log.error("请求开放平台查询会员信息接口失败");
			data.put("err_message", "系统异常，请稍后重试");
			return new ModelAndView("card/error",data);
		} else if (SysConstants.OPEN_SUCCESS.equals(memberInfoQueryOutput.getCode())) {
			WeChartMemberInfoQueryOutput.Result memberInfo = memberInfoQueryOutput.getResult();
			data.put("points", memberInfo.getPoints());
		} else {
			log.error("code：" + memberInfoQueryOutput.getCode());
			log.error("message：" + memberInfoQueryOutput.getMessage());
			data.put("err_message", memberInfoQueryOutput.getMessage());
			return new ModelAndView("card/error",data);
		}
		String weixinPointsRuleText = null;
		MerchantDefQueryInput merchantDefQueryInput = new MerchantDefQueryInput();
		merchantDefQueryInput.setMid(mid);
		MerchantDefInfoOutput merchantDefInfoOutput = (MerchantDefInfoOutput) wizarposOpenRestClient.post(merchantDefQueryInput, "/merchantdef/info/query", MerchantDefInfoOutput.class);
		if (merchantDefInfoOutput != null && SysConstants.OPEN_SUCCESS.equals(merchantDefInfoOutput.getCode())) {
			MerchantDefInfoOutput.Result result = merchantDefInfoOutput.getResult();
			if (result != null ) {
				JSONObject attachFields = (JSONObject) JSONObject.toJSON(result.getAttachFields());
				weixinPointsRuleText = attachFields.getString("weixinPointsRuleText");
			}
		}
		if (StringUtils.isEmpty(weixinPointsRuleText)) {
			weixinPointsRuleText = "暂无描述";
		}
		data.put("weixinPointsRuleText", weixinPointsRuleText);
		
		return new ModelAndView("card/card_integral", data);
	}

	/**
	 * 积分兑换列表页
	 * 
	 * @param mid
	 * @return
	 */
	@RequestMapping(value = "/exchange_integral")
	public ModelAndView exchangeIntegral(
			@RequestParam(value = "mid", required = true) String mid,
			HttpServletRequest httpRequest) {
		String cardId = (String) httpRequest.getSession().getAttribute("mrtCardId");
		String openId = (String) httpRequest.getSession().getAttribute("openId");
		if (StringUtils.isEmpty(cardId) || StringUtils.isEmpty(openId)) {//session过期，跳转到登录注册页面
			return new ModelAndView("forward:login");
		}
		
		Map<String, Object> data = new HashMap<String, Object>();
		// 请求开放平台查询会员卡信息
		WeChartMemberInfoQueryInput memberInfoQueryInput = new WeChartMemberInfoQueryInput();
		memberInfoQueryInput.setMid(mid);
		memberInfoQueryInput.setOpenId(openId);
		WeChartMemberInfoQueryOutput memberInfoQueryOutput = (WeChartMemberInfoQueryOutput) wizarposOpenRestClient.post(memberInfoQueryInput, "/wechart/info/query", WeChartMemberInfoQueryOutput.class);
		if (memberInfoQueryOutput == null) {
			log.error("请求开放平台查询会员卡信息接口失败");
			data.put("error_msg", "系统异常，请重试");// 其他错误，系统异常
			return new ModelAndView("card/error", data);
		} else if (SysConstants.OPEN_SUCCESS.equals(memberInfoQueryOutput.getCode()) && memberInfoQueryOutput.getResult() != null) {
			// 设置会员信息
			WeChartMemberInfoQueryOutput.Result memberInfo =  memberInfoQueryOutput.getResult();
			data.put("memberInfo", memberInfo);
		}  else if ("60007".equals(memberInfoQueryOutput.getCode())) {// 60007	会员不存在
			//若无会员卡，则前往会员卡领取页面领取会员卡
			return new ModelAndView("forward:receiveCard?mid" + mid);			
		} else {
			log.error("code: " + memberInfoQueryOutput.getCode());
			log.error("message: " + memberInfoQueryOutput.getMessage());
			data.put("error_msg", "系统异常，请重试");// 其他错误，系统异常
			return new ModelAndView("card/error", data);
		}
		
		// 请求开放平台可售券列表接口
		TicketMarketDefListInput ticketMarketDefListInput = new TicketMarketDefListInput();
		ticketMarketDefListInput.setMid(mid);
		ticketMarketDefListInput.setPageNo("1");
		TicketMarketDefListOutput ticketMarketDefListOutput = (TicketMarketDefListOutput) wizarposOpenRestClient.post(ticketMarketDefListInput, "/ticketmarket/ticketMarketDefList", TicketMarketDefListOutput.class);
		if (ticketMarketDefListOutput == null) {
			log.error("请求开放平台可售券列表接口失败");
			data.put("error_msg", "系统异常，请重试");// 其他错误，系统异常
			return new ModelAndView("card/error", data);
		} else if (SysConstants.OPEN_SUCCESS.equals(ticketMarketDefListOutput.getCode())) {
			// 可售券列表
			List<TicketMarketDef> ticketMarketDefList =  ticketMarketDefListOutput.getResult().getTicketMarketDef();
			data.put("ticketMarketDefList", ticketMarketDefList);				
		}  else {
			log.error("code: " + ticketMarketDefListOutput.getCode());
			log.error("message: " + ticketMarketDefListOutput.getMessage());
			data.put("error_msg", "系统异常，请重试");// 其他错误，系统异常
			return new ModelAndView("card/error", data);
		}
		data.put("mid", mid);
		return new ModelAndView("card/exchange_integral", data);
	}

	/**
	 * 积分兑换详情页
	 * 
	 * @param mid
	 * @return
	 */
	@RequestMapping(value = "/exchange_detail")
	public ModelAndView exchange_detail(
			@RequestParam(value = "mid", required = true) String mid,
			@RequestParam(value = "ticketDefId", required = true) String ticketDefId,
			HttpServletRequest httpRequest) {
		String cardId = (String) httpRequest.getSession().getAttribute("mrtCardId");
		if (StringUtils.isEmpty(cardId)) {//session过期，跳转到登录注册页面
			return new ModelAndView("forward:login");
		}
		Map<String, Object> data = new HashMap<String, Object>();
		
		// 请求开放平台可售券列表接口
		TicketMarketDefInput ticketMarketDefInput = new TicketMarketDefInput();
		ticketMarketDefInput.setMid(mid);
		ticketMarketDefInput.setTicketDefId(ticketDefId);
		TicketMarketDefOutput ticketMarketDefOutput = (TicketMarketDefOutput) wizarposOpenRestClient.post(ticketMarketDefInput, "/ticketmarket/ticketMarketDef", TicketMarketDefOutput.class);
		if (ticketMarketDefOutput == null) {
			log.error("请求开放平台可售券列表接口失败");
			data.put("error_msg", "系统异常，请重试");// 其他错误，系统异常
			return new ModelAndView("card/error", data);
		} else if (SysConstants.OPEN_SUCCESS.equals(ticketMarketDefOutput.getCode()) && ticketMarketDefOutput.getResult() != null) {
			// 可售券详情
			data.put("ticketMarketDef", ticketMarketDefOutput.getResult().getTicketMarketDef());				
		}  else {
			log.error("code: " + ticketMarketDefOutput.getCode());
			log.error("message: " + ticketMarketDefOutput.getMessage());
			data.put("error_msg", "系统异常，请重试");// 其他错误，系统异常
			return new ModelAndView("card/error", data);
		}
		data.put("mid", mid);
		return new ModelAndView("card/exchange_detail", data);
	}

	/**
	 * 积分兑换券
	 * 
	 * @param mid
	 * @return
	 */
	@RequestMapping(value = "/exchange_integral_submit")
	public @ResponseBody RespMessage exchangeIntegralSubmit(
			@RequestParam(value = "mid", required = true) String mid,
			@RequestParam(value = "ticketDefId", required = true) String ticketDefId,
			HttpServletRequest httpRequest) {
		RespMessage res = new RespMessage();
		String cardId = (String) httpRequest.getSession().getAttribute("mrtCardId");
		if (StringUtils.isEmpty(cardId)) {//session过期，跳转到登录注册页面
			res.setCode(2);
			return res;
		}
		
		// 请求开放平台可售券列表接口
		ExchangeIntegralInput exchangeIntegralInput = new ExchangeIntegralInput();
		exchangeIntegralInput.setMid(mid);
		exchangeIntegralInput.setTicketDefId(ticketDefId);
		exchangeIntegralInput.setCardId(cardId);
		ExchangeIntegralOutput exchangeIntegralOutput = (ExchangeIntegralOutput) wizarposOpenRestClient.post(exchangeIntegralInput, "/ticketmarket/exchangeIntegral", ExchangeIntegralOutput.class);
		if (exchangeIntegralOutput == null) {
			log.error("请求开放平台券营销积分兑换券订单提交接口失败");
			res.setMessage("系统异常，兑换失败");
			res.setCode(1);
			return res;
		} else if (SysConstants.OPEN_SUCCESS.equals(exchangeIntegralOutput.getCode())) {
			return res;		
		} else if ("60014".equals(exchangeIntegralOutput.getCode())) { // 积分不足兑换失败
			res.setCode(-1);
			res.setMessage(exchangeIntegralOutput.getMessage());
			return res;
		} else {
			log.error("code: " + exchangeIntegralOutput.getCode());
			log.error("message: " + exchangeIntegralOutput.getMessage());
			res.setMessage("系统异常，兑换失败");
			res.setCode(1);
			return res;
		}
	}
	
	/**
	 * 查询更多可兑换的券
	 * 
	 * @param mid
	 * @return
	 */
	@RequestMapping(value = "/more_exchange_ticket")
	@ResponseBody
	public RespMessage moreExchangeTicket(
			@RequestParam(value = "mid", required = true) String mid,
			@RequestParam(value = "nextPage", defaultValue = "1") Integer nextPage,
			HttpServletRequest httpRequest) {
		RespMessage res = new RespMessage();
		// 请求开放平台可售券列表接口
		TicketMarketDefListInput ticketMarketDefListInput = new TicketMarketDefListInput();
		ticketMarketDefListInput.setMid(mid);
		ticketMarketDefListInput.setPageNo(String.valueOf(nextPage));
		TicketMarketDefListOutput ticketMarketDefListOutput = (TicketMarketDefListOutput) wizarposOpenRestClient.post(ticketMarketDefListInput, "/ticketmarket/ticketMarketDefList", TicketMarketDefListOutput.class);
		if (ticketMarketDefListOutput == null) {
			log.error("请求开放平台可售券列表接口失败");
			res.setCode(-1);
			res.setMessage("系统异常，请重试");
			return res;
		} else if (SysConstants.OPEN_SUCCESS.equals(ticketMarketDefListOutput.getCode())) {
			// 可售券列表
			List<TicketMarketDef> ticketMarketDefList =  ticketMarketDefListOutput.getResult().getTicketMarketDef();
			res.setObj(ticketMarketDefList);
		}  else {
			log.error("code: " + ticketMarketDefListOutput.getCode());
			log.error("message: " + ticketMarketDefListOutput.getMessage());
			res.setCode(-1);
			res.setMessage("系统异常，请重试");
			return res;
		}
		return res;
	}

	/**
	 * 会员卡买单接口
	 * 
	 * @param mid
	 * @param amount
	 * @param ticketInfoIds
	 * @param httpRequest
	 * @return
	 */
	@RequestMapping(value = "/get_employees")
	@ResponseBody
	public RespMessage getEmployees(
			@RequestParam(value = "mid", required = true) String mid,
			HttpServletRequest httpRequest) {
		RespMessage res = new RespMessage();
		String cardId = (String) httpRequest.getSession().getAttribute("mrtCardId");
		if (StringUtils.isEmpty(cardId)) {//session过期，跳转到登录注册页面
			res.setCode(2);
			return res;
		}
		// 获取员工编号信息（东志信用）
		GetEmployeeslInput getEmployeeslInput = new GetEmployeeslInput();
		getEmployeeslInput.setMid(mid);
		GetEmployeesOutput getEmployeesOutput = (GetEmployeesOutput) wizarposOpenRestClient.post(getEmployeeslInput, "/dzx/get/employees", GetEmployeesOutput.class);
		if (getEmployeesOutput == null) {
			log.error("请求开放平台获取员工编号信息接口失败");
			log.error("mid="+mid);
			res.setCode(1);
			return res;
		} else if (SysConstants.OPEN_SUCCESS.equals(getEmployeesOutput.getCode())) {
			res.setObj(getEmployeesOutput.getResult().getEmployeePairs());
			return res;
		} else {
			log.error("code：" + getEmployeesOutput.getCode());
			log.error("message：" + getEmployeesOutput.getMessage());
			log.error("mid="+mid);
			res.setCode(1);
			return res;
		}
	}
	
	/**
	 * 会员卡买单接口
	 * 
	 * @param mid
	 * @param amount
	 * @param ticketInfoIds
	 * @param httpRequest
	 * @return
	 */
	@RequestMapping(value = "/pay_the_bill")
	@ResponseBody
	public RespMessage payTheBill(
			@RequestParam(value = "mid", required = true) String mid,
			@RequestParam(value = "amount", required = true) Integer amount,
			@RequestParam(value = "ticketInfoIds", required = true) String ticketInfoIds,
			@RequestParam(value = "shopMid", required = true) String shopMid,
			HttpServletRequest httpRequest) {
		RespMessage res = new RespMessage();
		String cardId = (String) httpRequest.getSession().getAttribute("mrtCardId");
		if (StringUtils.isEmpty(cardId)) {//session过期，跳转到登录注册页面
			res.setCode(2);
			return res;
		}
		// 请求开放平台买单接口
		PayTheBillInput payTheBillInput = new PayTheBillInput();
		payTheBillInput.setMid(mid);
		payTheBillInput.setAmount(amount);
		payTheBillInput.setCardId(cardId);
		payTheBillInput.setShopMid(shopMid);
		if (!StringUtils.isEmpty(ticketInfoIds)) {
			payTheBillInput.setTicketInfoIds(Arrays.asList(ticketInfoIds.split(",")));
		}
		PayTheBillOutput payTheBillOutput = (PayTheBillOutput) wizarposOpenRestClient.post(payTheBillInput, "/dzx/payTheBill", PayTheBillOutput.class);
		if (payTheBillOutput == null) {
			log.error("请求开放平台买单接口失败");
			res.setCode(1);
			return res;
		} else if (SysConstants.OPEN_SUCCESS.equals(payTheBillOutput.getCode())) {
			return res;
		} else if ("60010".equals(payTheBillOutput.getCode())) {
			res.setCode(-1);
			res.setMessage(payTheBillOutput.getMessage());
			return res;
		} else {
			log.error("code: " + payTheBillOutput.getCode());
			log.error("message: " + payTheBillOutput.getMessage());
			res.setCode(1);
			return res;
		}
	}
	
	/**
	 * 交易记录查询
	 * 
	 * @param mid
	 * @param nextPage
	 * @param httpRequest
	 * @return
	 */
	@RequestMapping(value = "/get_more_record")
	@ResponseBody
	public RespMessage getMoreRecord(
			@RequestParam(value = "mid", required = true) String mid,
			@RequestParam(value = "nextPage", defaultValue = "1") Integer nextPage,
			HttpServletRequest httpRequest) {
		RespMessage res = new RespMessage();
		String cardNo = (String) httpRequest.getSession().getAttribute("mrtCardNo");
		// 请求开放平台查询用户交易记录接口
		DzxTranLogInput tranLogInput = new DzxTranLogInput();
		tranLogInput.setMid(mid);
		tranLogInput.setCardNo(cardNo);
		tranLogInput.setPageNo(nextPage.toString());
		DzxTranLogOutput tranLogOutput = (DzxTranLogOutput) wizarposOpenRestClient.post(tranLogInput, "/dzx/tran/log", DzxTranLogOutput.class);
		if (tranLogOutput == null) {
			log.error("请求开放平台查询会员卡信息接口失败");
			res.setCode(2);
			return res;
		} else if (SysConstants.OPEN_SUCCESS.equals(tranLogOutput.getCode())) {
			List<DzxTranLogView> tranLogViews = tranLogOutput.getResult();
			List<TranLogVo> tranLogVos = new ArrayList<TranLogVo>();
			if (tranLogViews != null && tranLogViews.size() > 0) {
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				for (DzxTranLogView tranLogView : tranLogViews) {
					TranLogVo tranLogVo = new TranLogVo();
					String tranCode = tranLogView.getTranCode();
					if ("302".equals(tranCode)) {
						tranLogVo.setTranCode("充值");
					} else if ("304".equals(tranCode)) {
						tranLogVo.setTranCode("消费");
					} else if ("310".equals(tranCode)) {
						tranLogVo.setTranCode("消费撤销");
						tranLogView.setTranAmount(-tranLogView.getTranAmount());
					} else { // 309
						tranLogVo.setTranCode("充值撤销");
						tranLogView.setTranAmount(-tranLogView.getTranAmount());
					}
					tranLogVo.setTranTime(sdf.format(tranLogView.getTranTime()));
					tranLogVo.setTranAmount(Utils.changF2Y(tranLogView.getTranAmount()));
					tranLogVo.setBalance(Utils.changF2Y(tranLogView.getBalance()));
					tranLogVo.setMerchantName(tranLogView.getMerchantName());
					tranLogVos.add(tranLogVo);
				}
				res.setObj(tranLogVos);
			} else {
				res.setCode(1);
			}
			return res;
		} else {
			log.error("code: " + tranLogOutput.getCode());
			log.error("message: " + tranLogOutput.getMessage());
			res.setCode(2);
			return res;
		}
	}

	/**
	 * 会员积分明细（分页）查询
	 * 
	 * @param mid
	 * @param nextPage
	 * @param httpRequest
	 * @return
	 */
	@RequestMapping(value = "/get_more_points_record")
	@ResponseBody
	public RespMessage getMorePointsRecord(
			@RequestParam(value = "mid", required = true) String mid,
			@RequestParam(value = "nextPage", defaultValue = "1") Integer nextPage,
			HttpServletRequest httpRequest) {
		RespMessage res = new RespMessage();
		String cardId = (String) httpRequest.getSession().getAttribute("mrtCardId");
		// 请求开放平台会员积分明细（分页）
		MemberPointsDetailInput pointsDetailInput = new MemberPointsDetailInput();
		pointsDetailInput.setMid(mid);
		pointsDetailInput.setCardId(cardId);
		pointsDetailInput.setPageNo(nextPage);
		MemberPointsDetailOutput pointsDetailOutput = (MemberPointsDetailOutput) wizarposOpenRestClient.post(pointsDetailInput, "/wechart/points/detail", MemberPointsDetailOutput.class);
		if (pointsDetailOutput == null) {
			log.error("请求开放平台会员积分明细（分页）接口失败");
			res.setCode(2);
			return res;
		} else if (SysConstants.OPEN_SUCCESS.equals(pointsDetailOutput.getCode())) {
			List<PointsTranLog> pointsTranLogList = pointsDetailOutput.getResult().getPointsTranLogList();
			if (pointsTranLogList.size() < 1) {
				res.setCode(1);
			} else {
				res.setObj(pointsTranLogList);
			}
			return res;
		} else {
			log.error("code: " + pointsDetailOutput.getCode());
			log.error("message: " + pointsDetailOutput.getMessage());
			res.setCode(2);
			return res;
		}
	}
	
	/**
	 * 券明细查询
	 * 
	 * @param mid
	 * @param nextPage
	 * @param httpRequest
	 * @return
	 */
	@RequestMapping(value = "/get_more_ticket_record")
	@ResponseBody
	public RespMessage getMoreTicketRecord(
			@RequestParam(value = "mid", required = true) String mid,
			@RequestParam(value = "nextPage", defaultValue = "1") Integer nextPage,
			HttpServletRequest httpRequest) {
		RespMessage res = new RespMessage();
		String cardId = (String) httpRequest.getSession().getAttribute("mrtCardId");
		// 请求开放平台会员券明细（分页）
		MemberTicketDetailInput ticketDetailInput = new MemberTicketDetailInput();
		ticketDetailInput.setMid(mid);
		ticketDetailInput.setCardId(cardId);
		ticketDetailInput.setPageNo(nextPage);
		MemberTicketDetailOutput ticketDetailOutput = (MemberTicketDetailOutput) wizarposOpenRestClient.post(ticketDetailInput, "/wechart/ticket/detail", MemberTicketDetailOutput.class);
		if (ticketDetailOutput == null) {
			log.error("请求开放平台会员券明细（分页）接口失败");
			res.setCode(2);
			return res;
		} else if (SysConstants.OPEN_SUCCESS.equals(ticketDetailOutput.getCode())) {
			List<TicketTranLog> ticketTranLogs = ticketDetailOutput.getResult().getTicketTranLogs();
			if (ticketTranLogs.size() < 1) {
				res.setCode(1);
			} else {
				res.setObj(ticketTranLogs);
			}
			return res;
		} else {
			log.error("code: " + ticketDetailOutput.getCode());
			log.error("message: " + ticketDetailOutput.getMessage());
			res.setCode(2);
			return res;
		}
	}
	
	/**
	 * 交易记录查询
	 * @param openId
	 * @param mid
	 * @param tranType
	 * @param nextPage
	 * @return
	 * @author xudongdong
	 */
	@RequestMapping(value = "/get_record")
	@ResponseBody
	public List<TranLogView> getRecord(
			@RequestParam(value = "mid", required = true) String mid,
			@RequestParam(value = "nextPage", defaultValue = "1") Integer nextPage,
			HttpServletRequest httpRequest) {
		
		String cardNo = (String) httpRequest.getSession().getAttribute("mrtCardNo");
		
		ShopTranLogInput input = new ShopTranLogInput();
		input.setMid(mid);
		input.setCardNo(cardNo);
		input.setPageNo(nextPage.toString());
		ShopTranLogOutput output = (ShopTranLogOutput) wizarposOpenRestClient.post(input, "/wxshop/tran/log", ShopTranLogOutput.class);
		
		if (output != null && "0".equals(output.getCode())) {
			return output.getResult();
		}
		
		return null;
	}
	
	/**
	 * 查询交易记录
	 * 
	 * @param openId
	 * @param mid
	 * @return
	 */
	@RequestMapping(value = "/query_record")
	public ModelAndView queryRecord(
			@RequestParam(value = "mid", required = true) String mid,
			HttpServletRequest httpRequest) {
		String cardId = (String) httpRequest.getSession().getAttribute("mrtCardId");
		String cardNo = (String) httpRequest.getSession().getAttribute("mrtCardNo");
		String openId = (String) httpRequest.getSession().getAttribute("openId");
		
		if (StringUtils.isEmpty(openId) || StringUtils.isEmpty(cardId)
				|| StringUtils.isEmpty(cardNo)) {// session过期，跳转到登录注册页面
			return new ModelAndView("forward:login");
		}
		log.debug("query_record--------------------");
		log.debug("openId =" + openId);
		log.debug("mid =" + mid);

		Map<String, Object> data = new HashMap<String, Object>();
		data.put("cardId", cardId);
		data.put("cardNo", cardNo);
		data.put("mid", mid);
		data.put("error_msg", "");
		// 请求开放平台查询会员卡信息
		WeChartMemberInfoQueryInput memberInfoQueryInput = new WeChartMemberInfoQueryInput();
		memberInfoQueryInput.setMid(mid);
		memberInfoQueryInput.setOpenId(openId);
		WeChartMemberInfoQueryOutput memberInfoQueryOutput = (WeChartMemberInfoQueryOutput) wizarposOpenRestClient.post(memberInfoQueryInput, "/wechart/info/query", WeChartMemberInfoQueryOutput.class);
		if (memberInfoQueryOutput == null) {
			log.error("请求开放平台查询会员卡信息接口失败");
			data.put("error_msg", "系统异常，请重试");// 其他错误，系统异常
			return new ModelAndView("card/error", data);
		} else if (SysConstants.OPEN_SUCCESS.equals(memberInfoQueryOutput.getCode())) {
			Result result = memberInfoQueryOutput.getResult();
			// 查询余额
			data.put("balance", Utils.changF2Y(Integer.valueOf(result.getBalance())));			
		} else {
			log.error("code: " + memberInfoQueryOutput.getCode());
			log.error("message: " + memberInfoQueryOutput.getMessage());
			data.put("error_msg", "系统异常，请重试");// 其他错误，系统异常
			return new ModelAndView("card/error", data);
		}
		// 请求开放平台查询用户交易记录接口
		DzxTranLogInput tranLogInput = new DzxTranLogInput();
		tranLogInput.setMid(mid);
		tranLogInput.setCardNo(cardNo);
		tranLogInput.setPageNo("1");
		DzxTranLogOutput tranLogOutput = (DzxTranLogOutput) wizarposOpenRestClient.post(tranLogInput, "/dzx/tran/log", DzxTranLogOutput.class);
		if (tranLogOutput == null) {
			log.error("请求开放平台查询会员卡信息接口失败");
			data.put("error_msg", "系统异常，请重试");// 其他错误，系统异常
			return new ModelAndView("card/error", data);			
		} else if (SysConstants.OPEN_SUCCESS.equals(tranLogOutput.getCode())) {
			List<DzxTranLogView> tranLogViews = tranLogOutput.getResult();
			List<TranLogVo> tranLogVos = new ArrayList<TranLogVo>();
			if (tranLogViews != null && tranLogViews.size() > 0) {
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				for (DzxTranLogView tranLogView : tranLogViews) {
					TranLogVo tranLogVo = new TranLogVo();
					String tranCode = tranLogView.getTranCode();
					if ("302".equals(tranCode)) {
						tranLogVo.setTranCode("充值");
					} else if ("304".equals(tranCode)) {
						tranLogVo.setTranCode("消费");
					} else if ("310".equals(tranCode)) {
						tranLogVo.setTranCode("消费撤销");
						tranLogView.setTranAmount(-tranLogView.getTranAmount());
					} else { // 309
						tranLogVo.setTranCode("充值撤销");
						tranLogView.setTranAmount(-tranLogView.getTranAmount());
					}
					tranLogVo.setTranTime(sdf.format(tranLogView.getTranTime()));
					tranLogVo.setTranAmount(Utils.changF2Y(tranLogView.getTranAmount()));
					tranLogVo.setBalance(Utils.changF2Y(tranLogView.getBalance()));
					tranLogVo.setMerchantName(tranLogView.getMerchantName());
					tranLogVos.add(tranLogVo);
				}				
			}
			data.put("tranlogs", tranLogVos);
			return new ModelAndView("card/card_record", data);
		} else {
			log.error("code: " + tranLogOutput.getCode());
			log.error("message: " + tranLogOutput.getMessage());
			data.put("error_msg", "系统异常，请重试");// 其他错误，系统异常
			return new ModelAndView("card/error", data);			
		}
	}

	/**
	 * 我的记录（积分、券记录）
	 * 
	 * @param mid
	 * @param httpRequest
	 * @return
	 */
	@RequestMapping(value = "/my_record")
	public ModelAndView myRecord(
			@RequestParam(value = "mid", required = true) String mid,
			HttpServletRequest httpRequest) {
		String cardId = (String) httpRequest.getSession().getAttribute("mrtCardId");
		String cardNo = (String) httpRequest.getSession().getAttribute("mrtCardNo");
		String openId = (String) httpRequest.getSession().getAttribute("openId");
		
		if (StringUtils.isEmpty(openId) || StringUtils.isEmpty(cardId)
				|| StringUtils.isEmpty(cardNo)) {// session过期，跳转到登录注册页面
			return new ModelAndView("forward:login");
		}
		log.debug("query_record--------------------");

		Map<String, Object> data = new HashMap<String, Object>();
		data.put("mid", mid);
		// 请求开放平台查询会员卡信息
		WeChartMemberInfoQueryInput memberInfoQueryInput = new WeChartMemberInfoQueryInput();
		memberInfoQueryInput.setMid(mid);
		memberInfoQueryInput.setOpenId(openId);
		WeChartMemberInfoQueryOutput memberInfoQueryOutput = (WeChartMemberInfoQueryOutput) wizarposOpenRestClient.post(memberInfoQueryInput, "/wechart/info/query", WeChartMemberInfoQueryOutput.class);
		if (memberInfoQueryOutput == null) {
			log.error("请求开放平台查询会员卡信息接口失败");
			data.put("error_msg", "系统异常，请重试");// 其他错误，系统异常
			return new ModelAndView("card/error", data);
		} else if (SysConstants.OPEN_SUCCESS.equals(memberInfoQueryOutput.getCode())) {
			Result result = memberInfoQueryOutput.getResult();
			// 查询余额
			data.put("balance", Utils.changF2Y(Integer.valueOf(result.getBalance())));	
			data.put("points", result.getPoints());
		} else {
			log.error("code: " + memberInfoQueryOutput.getCode());
			log.error("message: " + memberInfoQueryOutput.getMessage());
			data.put("error_msg", "系统异常，请重试");// 其他错误，系统异常
			return new ModelAndView("card/error", data);
		}
		
		// 请求开放平台会员积分明细（分页）
		MemberPointsDetailInput pointsDetailInput = new MemberPointsDetailInput();
		pointsDetailInput.setMid(mid);
		pointsDetailInput.setCardId(cardId);
		pointsDetailInput.setPageNo(1);
		MemberPointsDetailOutput pointsDetailOutput = (MemberPointsDetailOutput) wizarposOpenRestClient.post(pointsDetailInput, "/wechart/points/detail", MemberPointsDetailOutput.class);
		if (pointsDetailOutput == null) {
			log.error("请求开放平台会员积分明细（分页）接口失败");
			data.put("error_msg", "系统异常，请重试");// 其他错误，系统异常
			return new ModelAndView("card/error", data);
		} else if (SysConstants.OPEN_SUCCESS.equals(pointsDetailOutput.getCode())) {
			// 积分明细
			data.put("pointsTranLogs", pointsDetailOutput.getResult().getPointsTranLogList());			
		} else {
			log.error("code: " + pointsDetailOutput.getCode());
			log.error("message: " + pointsDetailOutput.getMessage());
			data.put("error_msg", "系统异常，请重试");// 其他错误，系统异常
			return new ModelAndView("card/error", data);
		}
		
		// 请求开放平台会员券明细（分页）
		MemberTicketDetailInput ticketDetailInput = new MemberTicketDetailInput();
		ticketDetailInput.setMid(mid);
		ticketDetailInput.setCardId(cardId);
		ticketDetailInput.setPageNo(1);
		MemberTicketDetailOutput ticketDetailOutput = (MemberTicketDetailOutput) wizarposOpenRestClient.post(ticketDetailInput, "/wechart/ticket/detail", MemberTicketDetailOutput.class);
		if (ticketDetailOutput == null) {
			log.error("请求开放平台会员券明细（分页）接口失败");
			data.put("error_msg", "系统异常，请重试");// 其他错误，系统异常
			return new ModelAndView("card/error", data);
		} else if (SysConstants.OPEN_SUCCESS.equals(ticketDetailOutput.getCode())) {
			// 券明细
			data.put("ticketTranLogs", ticketDetailOutput.getResult().getTicketTranLogs());			
		} else {
			log.error("code: " + ticketDetailOutput.getCode());
			log.error("message: " + ticketDetailOutput.getMessage());
			data.put("error_msg", "系统异常，请重试");// 其他错误，系统异常
			return new ModelAndView("card/error", data);
		}
		return new ModelAndView("card/my_record", data);
	}

	@SuppressWarnings("unused")
	private List<Record> processRecordArray(JSONArray record) {
		List<Record> list = new ArrayList<Record>();
		for (int i = 0; i < record.size(); i++) {
			Record re = new Record();
			re.setBalance(Utils.changF2Y(record.getJSONObject(i).getIntValue(
					"balance")));
			long tranTime = record.getJSONObject(i).getLongValue("tranTime");
			re.setTranTime(Utils.long2DateTimeString(tranTime));
			re.setTranType(record.getJSONObject(i).getString("tranType"));
			re.setAmount(Utils.changF2Y(record.getJSONObject(i).getIntValue(
					"amount")));
			list.add(re);
		}
		return list;
	}
	
	/**
	 * 获取受理码生成二维码,会员卡
	 * 
	 * @param openId
	 * @param mid
	 * @param response
	 */
	@RequestMapping(value = "/get_qrcode")
	public void getQRcode(
			@RequestParam(value = "mid", required = true) String mid,
			String random, HttpServletResponse response, HttpServletRequest httpRequest) {
		String openId = (String) httpRequest.getSession().getAttribute("openId");
		log.debug("get_qrcode---------------");
		log.info("生成code mid:" + mid);
		try {
			JSONObject result = wposHttpClient.getQRcodeTokenId(openId, mid);
			int code = result.getIntValue("code");
			log.debug("code =" + code);
			log.debug("msg =" + result.getString("msg"));

			if (code == SysConstants.SUCCESS) {
				JSONObject token = result.getJSONObject("result");
				String content = token.getString("tokenId");
				OutputStream stream = response.getOutputStream();
				MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
				Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
				hints.put(EncodeHintType.MARGIN, 1);
				hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
				BitMatrix bitMatrix = multiFormatWriter.encode(content,
						BarcodeFormat.QR_CODE, 400, 400, hints);
				MatrixToImageWriter.writeToStream(bitMatrix, "png", stream);
			}
		} catch (Exception e) {
			log.error(e);
		}
	}

	/**
	 * 获取受理码生成二维码,慧银会员券
	 * 
	 * @param openId
	 * @param mid
	 * @param response
	 */
	@RequestMapping(value = "/ticket_qrcode")
	public void ticketQRcode(
			@RequestParam(value = "ticketNo", required = true) String ticketNo,
			HttpServletResponse response, HttpServletRequest httpRequest) {
		try {
			OutputStream stream = response.getOutputStream();
			MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
			Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
			hints.put(EncodeHintType.MARGIN, 1);
			hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
			BitMatrix bitMatrix = multiFormatWriter.encode(ticketNo,
					BarcodeFormat.QR_CODE, 400, 400, hints);
			MatrixToImageWriter.writeToStream(bitMatrix, "png", stream);
		} catch (Exception e) {
			log.error(e);
		}
	}
	
	@RequestMapping(value = "/shopaddress")
	public ModelAndView shopaddress(
			@RequestParam(value = "mid", required = true) String mid,
			HttpServletRequest httpRequest) {
		
		Map<String, Object> data = new HashMap<String, Object>();
		// 商户数据
		ShopAddressInput shopAddressInput = new ShopAddressInput();
		shopAddressInput.setMid(mid);
		ShopAddressOutput shopAddressOutput = (ShopAddressOutput) wizarposOpenRestClient.post(shopAddressInput, "/dzx/shopAddress", ShopAddressOutput.class);		
		if (shopAddressOutput == null) {
			log.error("请求开发平台会员卡页门店信息（东志信用）接口失败");
			data.put("error_msg", SysConstants.OPEN_ERROR_MESSAGE);
			return new ModelAndView("card/error",data);
		} else if (!SysConstants.OPEN_SUCCESS.equals(shopAddressOutput.getCode())) {
			log.error("code：" + shopAddressOutput.getCode());
			log.error("message：" + shopAddressOutput.getMessage());
			data.put("error_msg", "系统错误，请重试");
		}
		ShopAddressOutput.Result results = shopAddressOutput.getResult();
		List<ShopAddressPair> shopAddressPairs = results.getShopAddressPairs();
		JSONArray lonLats = new JSONArray();
		for (ShopAddressPair shopAddressPair : shopAddressPairs) {
			JSONObject json = new JSONObject();
			json.put("lon", shopAddressPair.getLon());
			json.put("lat", shopAddressPair.getLat());
			lonLats.add(json);
		}
		data.put("lonLats", lonLats.toJSONString());
		data.put("shopAddressPairs", results.getShopAddressPairs());

		
		// 请求微信api的ticket
		AccessTokenInput jsInput = new AccessTokenInput();
		jsInput.setMid(mid);
		CommonResultOutput jsOutput = (CommonResultOutput) wizarposOpenRestClient.post(jsInput, "/weixin/ticket/js", CommonResultOutput.class);		
		if (jsOutput == null || SysConstants.OPEN_ERROR.equals(jsOutput.getCode())) {// 请求开放平台出错
			data.put("error_msg", "系统错误，请重试");
			return new ModelAndView("card/error",data);
		} else if (SysConstants.NO_MERCHANT_CODE.equals(jsOutput.getCode())) {// 非法的慧商户号
			data.put("error_msg", SysConstants.NO_MERCHANT);
			return new ModelAndView("card/error",data);
		} else {
			Map<String, String> jsResult = (Map<String, String>) jsOutput.getResult();
			String jsTicket = jsResult.get("ticket");
			String appid = jsResult.get("appid");
			data.put("appId", appid);
			// 请求微信 js api的完整页面地址
			String baseUrl = getBaseURL(httpRequest);
			StringBuffer tmpUrl = new StringBuffer();
			tmpUrl.append(baseUrl);
			tmpUrl.append("/vip/shopaddress");
			tmpUrl.append("?mid=").append(mid);
			String url = tmpUrl.toString();
			
			Map<String, String> ret = WxSignUtil.commonSign(jsTicket, url,
					WxSignUtil.createTimestamp());
			data.putAll(ret);
			
			AccessTokenOutput accessOutput = (AccessTokenOutput) wizarposOpenRestClient.post(jsInput, "/weixin/accesstoken", AccessTokenOutput.class);		
			String accessToken = null;
			if (accessOutput != null && SysConstants.OPEN_SUCCESS.equals(accessOutput.getCode())) {
				cn.congine.wizarpos.mall.model.open.AccessTokenOutput.Result result = accessOutput.getResult();
				if (result != null) {
					accessToken = result.getToken();
					// weixin js 地址api 签名
					String retLoc = WxSignUtil.signLocation(accessToken, appid, url,
							ret.get("timestamp"), ret.get("noncestr"));
					data.put("addrSign", retLoc);
				} else {
					data.put("error_msg", "系统错误，请重试");
					return new ModelAndView("card/error",data);		
				}
			} else {
				data.put("error_msg", "系统错误，请重试");
				return new ModelAndView("card/error",data);
			}
			
		}
		return new ModelAndView("card/shop_address", data);
	}
	
	/**
	 * 距离门店位置
	 * 
	 * @param mid
	 * @param longitude
	 * @param latitude
	 * @param shopLongitude
	 * @param shopLatitude
	 * @return
	 */
	@RequestMapping(value = "/getdistance")
	public @ResponseBody String getdistance(
			@RequestParam(value = "mid", required = true) String mid,
			@RequestParam(value = "longitude", required = true) String longitude,
			@RequestParam(value = "latitude", required = true) String latitude,
			@RequestParam(value = "shopLongitude", required = true) String shopLongitude,
			@RequestParam(value = "shopLatitude", required = true) String shopLatitude) {
		
		String distance = "";
		
		if (longitude != null 
				&& latitude != null 
				&& !"0".equals(shopLongitude) 
				&& !"0".equals(shopLatitude)) {
			double k = distance(
					Double.valueOf(longitude), 
					Double.valueOf(latitude), 
					Double.valueOf(shopLongitude),
					Double.valueOf(shopLatitude));
			
			if (k > 1000) {
				k = k / 1000f;
				String format = String
						.format("%.1f", k);
				distance = "" + format + "公里";
			} else {
				distance = "" + Double.valueOf(k).intValue() + "米";
			}
		}
		
		return distance;
	}

	/**
	 * 距离门店位置
	 * 
	 * @param mid
	 * @param longitude
	 * @param latitude
	 * @param shopLongitude
	 * @param shopLatitude
	 * @return
	 */
	@RequestMapping(value = "/calDistance")
	public @ResponseBody RespMessage calDistance(
			@RequestParam(value = "longitude", required = true) String longitude,
			@RequestParam(value = "latitude", required = true) String latitude,
			@RequestParam(value = "shopInfoPairs", required = true) String shopInfoPairs) {
		RespMessage res = new RespMessage();
		
		List<ShopInfoPair> shopInfoPairList = JSONObject.parseArray(shopInfoPairs, ShopInfoPair.class);
		if (shopInfoPairList != null && !shopInfoPairList.isEmpty()) {
			for (ShopInfoPair shopInfoPair : shopInfoPairList) {
				String lon = shopInfoPair.getLon();
				String lat = shopInfoPair.getLat();
				if (!StringUtils.isEmpty(lon) && !"0".equals(lon) && !StringUtils.isEmpty(lat) && !"0".equals(lat) ) {
					String distance = "";
					double k = distance(
							Double.valueOf(longitude), 
							Double.valueOf(latitude), 
							Double.valueOf(lon),
							Double.valueOf(lat));
					shopInfoPair.setCalDistance(k);
					if (k > 1000) {
						k = k / 1000f;
						String format = String
								.format("%.1f", k);
						distance = "" + format + "公里";
					} else {
						distance = "" + Double.valueOf(k).intValue() + "米";
					}
					shopInfoPair.setDistance(distance);
				} else {
					shopInfoPair.setDistance("未知");
					shopInfoPair.setCalDistance(0d);
				}
			}
			Collections.sort(shopInfoPairList, new Comparator<ShopInfoPair>() {
				public int compare(ShopInfoPair a, ShopInfoPair b) {
					return a.getCalDistance().compareTo(b.getCalDistance());
				}
			});
			res.setObj(JSON.toJSONString(shopInfoPairList, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNonStringKeyAsString));
			return res;
		}
		return res;
	}
	
	/**
	 * 计算两个点之间距离（单位米）
	 * 
	 * @param long1
	 * @param lat1
	 * @param long2
	 * @param lat2
	 * @return
	 */
	private static double distance(double long1, double lat1, double long2,
			double lat2) {
		double a, b, R;
		R = 6378137; // 地球半径
		lat1 = lat1 * Math.PI / 180.0;
		lat2 = lat2 * Math.PI / 180.0;
		a = lat1 - lat2;
		b = (long1 - long2) * Math.PI / 180.0;
		double d;
		double sa2, sb2;
		sa2 = Math.sin(a / 2.0);
		sb2 = Math.sin(b / 2.0);
		d = 2
				* R
				* Math.asin(Math.sqrt(sa2 * sa2 + Math.cos(lat1)
						* Math.cos(lat2) * sb2 * sb2));
		return d;
	}
	/**
	 * 跳转到券列表页面
	 * 
	 * @param openId
	 * @param mid
	 * @return
	 * @throws Exception
	 * @author xudongdong
	 */
	@RequestMapping(value = "/ticket_list")
	public ModelAndView ticketList(
			@RequestParam(value = "mid", required = true) String mid,
			HttpServletRequest httpRequest) throws Exception {	
		String cardId = (String) httpRequest.getSession().getAttribute("mrtCardId");
		if (StringUtils.isEmpty(cardId)) {//session过期，跳转到登录注册页面
			return new ModelAndView("forward:login");
		}
		TicketListInput input = new TicketListInput();
		input.setMid(mid);
		input.setCardId(cardId);
		TicketListOutput output = (TicketListOutput) wizarposOpenRestClient.post(input, "/wechart/ticket_list", TicketListOutput.class);
		
		Map<String, Object> data = new HashMap<String, Object>();
		data.put("mid", mid);
		data.put("error_msg", "");
		
		//非法慧商户号
		if ("60001".equals(output.getCode())) {
			data.put("error_msg", SysConstants.NO_MERCHANT);
			return new ModelAndView("card/error", data);
		}
		
		data.put("ticket_counts", output.getNum());
		data.put("ticket_list", output.getTicketList());
		// 请求微信 js api的完整页面地址
		String baseUrl = getBaseURL(httpRequest);
		StringBuffer tmpUrl = new StringBuffer();
		tmpUrl.append(baseUrl);
		tmpUrl.append("/vip/ticket_list");
		tmpUrl.append("?wechat_card_js=1");
		tmpUrl.append("&mid=").append(mid);
		String url = tmpUrl.toString();
		// 请求微信api的ticket
		AccessTokenInput jsInput = new AccessTokenInput();
		jsInput.setMid(mid);
		CommonResultOutput jsOutput = (CommonResultOutput) wizarposOpenRestClient.post(jsInput, "/weixin/ticket/js", CommonResultOutput.class);		
		if (jsOutput == null || SysConstants.OPEN_ERROR.equals(jsOutput.getCode())) {
			return new ModelAndView("error").addObject("err_message",
					SysConstants.OPEN_ERROR);
		} else if (SysConstants.NO_MERCHANT_CODE.equals(jsOutput.getCode())) {
			return new ModelAndView("error").addObject("err_message",
					SysConstants.NO_MERCHANT);
		} else {
			Map<String, String> result = (Map<String, String>) jsOutput.getResult();
			String jsTicket = result.get("ticket");
			String appid = result.get("appid");
			data.put("appId", appid);
			Map<String, String> ret = WxSignUtil.commonSign(jsTicket, url,
					WxSignUtil.createTimestamp());
			data.putAll(ret);
		}			

		return new ModelAndView("card/ticket_list", data);
	}

	/**
	 * 我的卡包
	 * 
	 * @param mid
	 * @param httpRequest
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/card_holder")
	public ModelAndView cardHolder(
			@RequestParam(value = "mid", required = true) String mid,
			HttpServletRequest httpRequest) throws Exception {	
		String cardNo = (String) httpRequest.getSession().getAttribute("mrtCardNo");
		if (StringUtils.isEmpty(cardNo)) {//session过期，跳转到登录注册页面
			return new ModelAndView("forward:login");
		}
		Map<String, Object> data = new HashMap<String, Object>();
		WeChartMemberCardHolderInput memberCardHolderInput = new WeChartMemberCardHolderInput();
		memberCardHolderInput.setMid(mid);
		memberCardHolderInput.setCardNo(cardNo);
		WeChartMemberCardHolderOutput memberCardHolderOutput = (WeChartMemberCardHolderOutput) wizarposOpenRestClient.post(memberCardHolderInput, "/wechart/cardHolder", WeChartMemberCardHolderOutput.class);
		
		if (memberCardHolderOutput == null) {
			log.error("请求开放平台我的卡包（券列表，按券类型划分）接口失败");
			data.put("error_msg", "系统错误，请重试");
			return new ModelAndView("card/error", data);
		} else if (!SysConstants.OPEN_SUCCESS.equals(memberCardHolderOutput.getCode())) {
			log.error("code：" + memberCardHolderOutput.getCode());
			log.error("message：" + memberCardHolderOutput.getMessage());
			data.put("error_msg", "系统错误，请重试");
			return new ModelAndView("card/error", data);
		}
		WeChartMemberCardHolderOutput.Result result = memberCardHolderOutput.getResult();
		data.put("logoImage", result.getLogoImage());
		data.put("marchantName", result.getMerchantName());		
		data.put("mid", mid);
		data.put("cardHolders", result.getCardHolders());

		return new ModelAndView("card/card_holder", data);
	}
	
	/**
	 * 跳转到券列表页面（新版）
	 * 
	 * @param mid
	 * @param httpRequest
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/ticket_info_list")
	public ModelAndView tickeInfotList(
			@RequestParam(value = "mid", required = true) String mid,
			@RequestParam(value = "ticketDefId", required = false) String ticketDefId,
			HttpServletRequest httpRequest) throws Exception {	
		String cardId = (String) httpRequest.getSession().getAttribute("mrtCardId");
		if (StringUtils.isEmpty(cardId)) {//session过期，跳转到登录注册页面
			return new ModelAndView("forward:login");
		}
		Map<String, Object> data = new HashMap<String, Object>();
		
		TicketInfoListInput input = new TicketInfoListInput();
		input.setMid(mid);
		input.setCardId(cardId);
		input.setTicketDefId(ticketDefId);
		TicketInfoListOutput output = (TicketInfoListOutput) wizarposOpenRestClient.post(input, "/wechart/ticket_info_list", TicketInfoListOutput.class);

		if (output != null && "0".equals(output.getCode())) {
			cn.congine.wizarpos.mall.model.open.TicketInfoListOutput.Result result = output.getResult();
			if (result != null) {
				List<TicketInfoVo> ticketInstsToExpired = result.getTicketToExpiredList();
				List<TicketInfoVo> ticketInstsNormal = result.getTicketList();
				data.put("ticketInstsToExpired", ticketInstsToExpired);
				data.put("ticketInstsNormal", ticketInstsNormal);
			}
			data.put("logoImage", result.getLogoImage());
			data.put("marchantName", result.getMerchantName());
			data.put("mid", mid);
			
		} else if (output == null) {
			data.put("error_msg", "系统错误，请重试");
			return new ModelAndView("card/error", data);
		} else if ("60001".equals(output.getCode())) {// 非法慧商户号
			data.put("error_msg", SysConstants.NO_MERCHANT);
			return new ModelAndView("card/error", data);
		}			

		return new ModelAndView("card/ticket_list", data);
	}

	/**
	 * 卡券详情页一
	 * 
	 * @param mid
	 * @param httpRequest
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/ticket_info_detail")
	public ModelAndView tickeInfoDetail(
			@RequestParam(value = "mid", required = true) String mid,
			@RequestParam(value = "ticketNo", required = true) String ticketNo,
			HttpServletRequest httpRequest) throws Exception {	
		Map<String, Object> data = new HashMap<String, Object>();
		
		TicketInfoDetailInput input = new TicketInfoDetailInput();
		input.setMid(mid);
		input.setTicketNo(ticketNo);
		TicketInfoDetailOutput output = (TicketInfoDetailOutput) wizarposOpenRestClient.post(input, "/wechart/ticket_info_detail", TicketInfoDetailOutput.class);
		
		if (output != null && "0".equals(output.getCode())) {
			cn.congine.wizarpos.mall.model.open.TicketInfoDetailOutput.Result result = output.getResult();
			if (result != null) {
				// 请求微信 js api的完整页面地址
				String baseUrl = getBaseURL(httpRequest);
				StringBuffer tmpUrl = new StringBuffer();
				tmpUrl.append(baseUrl);
				tmpUrl.append("/vip/ticket_info_detail");
				tmpUrl.append("?wechat_card_js=1");
				tmpUrl.append("&mid=").append(mid);
				tmpUrl.append("&ticketNo=").append(ticketNo);
				String url = tmpUrl.toString();
				// 请求微信api的ticket
				AccessTokenInput jsInput = new AccessTokenInput();
				jsInput.setMid(mid);
				CommonResultOutput jsOutput = (CommonResultOutput) wizarposOpenRestClient.post(jsInput, "/weixin/ticket/js", CommonResultOutput.class);		
				if (jsOutput == null) {// 请求开放平台出错
					return new ModelAndView("error").addObject("err_message",
							SysConstants.OPEN_ERROR_MESSAGE);
				} else if (SysConstants.NO_MERCHANT_CODE.equals(jsOutput.getCode())) {// 非法的慧商户号
					return new ModelAndView("error").addObject("err_message",
							SysConstants.NO_MERCHANT);
				} else if (!SysConstants.OPEN_SUCCESS.equals(jsOutput.getCode())) {
					return new ModelAndView("error").addObject("err_message",
							SysConstants.OPEN_ERROR_MESSAGE);
				} else {
					Map<String, String> jsResult = (Map<String, String>) jsOutput.getResult();
					String jsTicket = jsResult.get("ticket");
					String appid = jsResult.get("appid");
					data.put("appId", appid);
					Map<String, String> ret = WxSignUtil.commonSign(jsTicket, url,
							WxSignUtil.createTimestamp());
					data.putAll(ret);
				}
				
				data.put("ticketName", result.getTicketName());
				data.put("description", result.getDescription());
				if (result.getValidPeriod() == -1) {
					data.put("expriyTime", "永久有效");
				} else {
					data.put("startTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(result.getStartTime()));
					data.put("expriyTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(result.getExpriyTime()));
				}
				data.put("ticketNo", result.getTicketNo());
				data.put("wxCodeId", result.getWxCodeId());
				data.put("wxCustomCode", result.getWxCustomCode());
				data.put("wxFlag", result.getWxFlag());
				data.put("wxAdded", result.getWxAdded());
				data.put("logoImage", result.getLogoImage());
				data.put("merchantName", result.getMerchantName());	
				data.put("mid", mid);
			} else {
				data.put("error_msg", "系统错误，请重试");
				return new ModelAndView("card/error", data);
			}
		} else if (output == null) {
			data.put("error_msg", "系统错误，请重试");
			return new ModelAndView("card/error", data);
		} else if ("60001".equals(output.getCode())) {// 非法慧商户号
			data.put("error_msg", SysConstants.NO_MERCHANT);
			return new ModelAndView("card/error", data);
		} else if ("60011".equals(output.getCode())) {// 未知的卡券
			data.put("error_msg", "未知的卡券");
			return new ModelAndView("card/error", data);	
		} else {
			data.put("error_msg", "系统错误，请重试");
			return new ModelAndView("card/error", data);
		}

		return new ModelAndView("card/ticket_detail", data);
	}

	/**
	 * 卡券详情页二
	 * 
	 * @param mid
	 * @param httpRequest
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/ticket_detail")
	public ModelAndView tickeDetail(
			@RequestParam(value = "mid", required = true) String mid,
			@RequestParam(value = "ticketNo", required = true) String ticketNo,
			HttpServletRequest httpRequest) throws Exception {	
		Map<String, Object> data = new HashMap<String, Object>();
		
		TicketInfoDetailInput input = new TicketInfoDetailInput();
		input.setMid(mid);
		input.setTicketNo(ticketNo);
		TicketInfoDetailOutput output = (TicketInfoDetailOutput) wizarposOpenRestClient.post(input, "/wechart/ticket_info_detail", TicketInfoDetailOutput.class);
		
		if (output != null && "0".equals(output.getCode())) {
			cn.congine.wizarpos.mall.model.open.TicketInfoDetailOutput.Result result = output.getResult();
			if (result != null) {
				data.put("description", result.getDescription());		
			} else {
				data.put("error_msg", "系统错误，请重试");
				return new ModelAndView("card/error", data);
			}
			
		} else if (output == null) {
			data.put("error_msg", "系统错误，请重试");
			return new ModelAndView("card/error", data);
		} else if ("60001".equals(output.getCode())) {// 非法慧商户号
			data.put("error_msg", SysConstants.NO_MERCHANT);
			return new ModelAndView("card/error", data);
		} else if ("60011".equals(output.getCode())) {// 未知的卡券
			data.put("error_msg", "未知的卡券");
			return new ModelAndView("card/error", data);	
		} else {
			data.put("error_msg", "系统错误，请重试");
			return new ModelAndView("card/error", data);
		}

		return new ModelAndView("card/archdetail", data);
	}
	
	/**
	 * 领取券的记录
	 * @param mid
	 * @param openId
	 * @param nextPage
	 * @return
	 * @author xudongdong
	 */
	@RequestMapping(value = "/get_ticket")
	@ResponseBody
	public List<Object> getTicket(
			@RequestParam(value = "mid", required = true) String mid,
			@RequestParam(value = "cardId", required = true) String cardId,
			@RequestParam(value = "nextPage", defaultValue = "1") String nextPage) {
		TicketAddDetailInput input = new TicketAddDetailInput();
		input.setMid(mid);
		input.setCardId(cardId);
		input.setPageNo(nextPage);
		TicketAddDetailOutput output = (TicketAddDetailOutput) wizarposOpenRestClient.post(input, "/wechart/ticket/add/detail", TicketAddDetailOutput.class);		
		if (output != null) {
			return output.getTicketInfoList();
		}
		return null;
	}	
	
	/**
	 * 券的使用记录
	 * 
	 * @param mid
	 * @param openId
	 * @param nextPage
	 * @return
	 * @author xudongdong
	 */
	@RequestMapping(value = "/get_used_ticket")
	public 	@ResponseBody List<TicketUseLog> get_used_ticket(
			@RequestParam(value = "mid", required = true) String mid,
			@RequestParam(value = "cardId", required = true) String cardId,
			@RequestParam(value = "nextPage", defaultValue = "1") String nextPage) {
		
		TicketUseLogInput input = new TicketUseLogInput();
		input.setMid(mid);
		input.setCardId(cardId);
		input.setPageNo(nextPage);
		TicketUseLogOutput output = (TicketUseLogOutput) wizarposOpenRestClient.post(input, "/wxshop/ticket/use/log", TicketUseLogOutput.class);		
		if (output != null && "0".equals(output.getCode())) {
			return output.getResult();
		}
		return null;		
	}	

	protected String getMid(String mid) {
		StringBuffer buffer = new StringBuffer();
		StringBuffer buffer1 = new StringBuffer();
		/* String mid = "05101111"; */
		String middle = mid.substring(1, 3);
		char pre = mid.charAt(0);
		String aa = mid.substring(4);
		for (int i = 0; i <= 7 - aa.length(); i++) {
			buffer1.append("0");
		}
		buffer.append("100").append(pre).append("0").append(middle)
				.append(buffer1).append(aa);
		return buffer.toString();
	}

	/**
	 * 券修改 微信券添加到卡包时
	 * @param wxCardId
	 * @param ticketNo
	 * @param openId
	 * @param mid
	 * @param httpRequest
	 * @return
	 * @author xudongdong
	 */
	@RequestMapping(value = "/flag_ticket")
	@ResponseBody
	public RespMessage flagTicket(
			@RequestParam(value = "wxCardId", required = true) String wxCardId,
			@RequestParam(value = "ticketNo", required = true) String ticketNo,
			@RequestParam(value = "mid", required = true) String mid,
			HttpServletRequest httpRequest) {
		RespMessage res = new RespMessage();
		String cardId = (String) httpRequest.getSession().getAttribute("mrtCardId");
		if (StringUtils.isEmpty(cardId)) {//session过期，跳转到登录注册页面
			res.setCode(2);
			return res;
		}		
		TicketToPackageInput input = new TicketToPackageInput();
		input.setMid(mid);
		input.setCardId(cardId);
		input.setWxCardId(wxCardId);
		input.setTicketNo(ticketNo);
		TicketToPackageOutput output = (TicketToPackageOutput) wizarposOpenRestClient.post(input, "/wechart/ticket/topackage", TicketToPackageOutput.class);						
		//return new ModelAndView("forward:my_card");
		if (output != null && "0".equals(output.getCode())) {//0操作成功
			res.setCode(0);
			return res;		
		} else {
			res.setCode(1);
			res.setMessage(output.getMessage());
			return res;
		}
		
	}

	/**
	 * 绑定非会员卡
	 * 
	 * @param ticketNo
	 * @param openId
	 * @param mid
	 * @return
	 */
	@RequestMapping(value = "/binding")
	public @ResponseBody RespMessage binding(
			@RequestParam(value = "ticketNo", required = true) String ticketNo,
			@RequestParam(value = "mid", required = true) String mid,
			HttpServletRequest httpRequest) {
		RespMessage res = new RespMessage();
		String cardId = (String) httpRequest.getSession().getAttribute("mrtCardId");
		if (StringUtils.isEmpty(cardId)) {//session过期，跳转到登录注册页面
			res.setCode(2);
			return res;	
		}
 		TicketBindingInput input = new TicketBindingInput();
		input.setMid(mid);
		input.setCardId(cardId);
		input.setTicketNo(ticketNo);
		TicketBindingOutput output = (TicketBindingOutput) wizarposOpenRestClient.post(input, "/wechart/ticket/banding", TicketBindingOutput.class);
		String code = output.getCode();
		if ("60011".equals(code)) { //未知的卡券
			res.setCode(1);
			return res;	
		} else if ("60036".equals(code)) { //卡券已被绑定
			res.setCode(3);
			return res;	
		} else { //绑定成功
			res.setCode(0);
			return res;	
		}		
	}
	
	/**
	 * 进入绑定非会员卡页
	 * 
	 * @param ticketNo
	 * @param openId
	 * @param mid
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/tobinding")
	public ModelAndView toBinding(
			@RequestParam(value = "mid", required = true) String mid,
			HttpServletRequest httpRequest) throws Exception {
		String openId = (String) httpRequest.getSession().getAttribute("openId");
		if (StringUtils.isEmpty(openId)) {//session过期，跳转到登录注册页面
			return new ModelAndView("forward:login");
		}
		Map<String, Object> data = new HashMap<String, Object>();
		data.put("mid", mid);
		
		// 请求微信 js api的完整页面地址
		String baseUrl = getBaseURL(httpRequest);
		StringBuffer tmpUrl = new StringBuffer();
		tmpUrl.append(baseUrl);
		tmpUrl.append("/vip/tobinding");
		tmpUrl.append("?mid=").append(mid);
		String url = tmpUrl.toString();
		
		// 请求微信api的ticket
		AccessTokenInput jsInput = new AccessTokenInput();
		jsInput.setMid(mid);
		CommonResultOutput jsOutput = (CommonResultOutput) wizarposOpenRestClient.post(jsInput, "/weixin/ticket/js", CommonResultOutput.class);		
		if (jsOutput == null || SysConstants.OPEN_ERROR.equals(jsOutput.getCode())) {
			return new ModelAndView("error").addObject("err_message",
					SysConstants.OPEN_ERROR);
		} else if (SysConstants.NO_MERCHANT_CODE.equals(jsOutput.getCode())) {
			return new ModelAndView("error").addObject("err_message",
					SysConstants.NO_MERCHANT);
		} else {
			Map<String, String> result = (Map<String, String>) jsOutput.getResult();
			String jsTicket = result.get("ticket");
			String appid = result.get("appid");
			data.put("appId", appid);
			Map<String, String> ret = WxSignUtil.commonSign(jsTicket, url,
					WxSignUtil.createTimestamp());
			data.putAll(ret);
		}
		
		return new ModelAndView("card/binding", data);
	}
	
	private String getBaseURL(HttpServletRequest httpRequest) {
		String baseUrl = "http://"
				+ messageSource.getMessage(SysConstants.SERVICE_DNS, null,
						Locale.ENGLISH);
		baseUrl += httpRequest.getSession().getServletContext().getContextPath();
		return baseUrl;
	}
	
	@RequestMapping(value = "/error")
	@ResponseBody
	public ModelAndView error(String msg) throws UnsupportedEncodingException {
		return new ModelAndView("card/error").addObject("error_msg", URLDecoder.decode(msg, "UTF-8"));
	}
	
	/**
	 * 送短信验证码
	 * 
	 * @param mid
	 * @param phone
	 * @param httpRequest
	 * @return
	 */
	@RequestMapping(value = "/send_verification_code")
	@ResponseBody
	public RespMessage sendVerificationCode(
			@RequestParam(value = "mid", required = true) String mid,
			@RequestParam(value = "phone", required = true) String phone,
			HttpServletRequest httpRequest) {
		RespMessage res = new RespMessage();
		// 发送短信验证码
		JSONObject resJson = wposHttpClient.sendVerificationCode(mid, phone);
		if (resJson != null && "0".equals(resJson.getString("code"))) {
			return res;
		} else {
			res.setCode(-1);
			res.setMessage("发送短信验证码失败");
			return res;
		}
	}

	/**
	 * 发送短信验证码
	 * type：1 会员卡注册    5 密码修改 
	 * 
	 * @param mid
	 * @param phone
	 * @param type
	 * @param httpRequest
	 * @return
	 */
	@RequestMapping(value = "/send_vcode")
	@ResponseBody
	public RespMessage sendVcode(
			@RequestParam(value = "mid", required = true) String mid,
			@RequestParam(value = "phone", required = true) String phone,
			@RequestParam(value = "type", required = true) String type,
			HttpServletRequest httpRequest) {
		RespMessage res = new RespMessage();
		String cardNo = (String) httpRequest.getSession().getAttribute("mrtCardNo");
		// 密码修改
		if ("5".equals(type) && StringUtils.isEmpty(cardNo)) {//session过期，跳转到登录注册页面
			res.setCode(2);
			return res;	
		}
		// 发送短信验证码（修改交易密码用）
		JSONObject resJson = wposHttpClient.sendVcode(mid, phone, cardNo, type);
		if (resJson != null && "0".equals(resJson.getString("code"))) {
			return res;
		} else {
			if (resJson == null) {
				log.error("请求member-server外卖退单1051接口失败");
			} else {
				log.error(resJson.toString());
			}
			res.setCode(-1);
			res.setMessage("发送短信验证码失败");
			return res;
		}
	}
	
	/**
	 * 校验短信验证码
	 * 
	 * @param mid
	 * @param phone
	 * @param vcode
	 * @param httpRequest
	 * @return
	 */
	@RequestMapping(value = "/check_verification_code")
	@ResponseBody
	public RespMessage checkVerificationCode(
			@RequestParam(value = "mid", required = true) String mid,
			@RequestParam(value = "phone", required = true) String phone,
			@RequestParam(value = "vcode", required = true) String vcode,
			@RequestParam(value = "msgType", required = true) String msgType,
			HttpServletRequest httpRequest) {
		RespMessage res = new RespMessage();
		// 请求开放平台校验短信验证码接口
		CheckVerificationCodeInput input = new CheckVerificationCodeInput();
		input.setMid(mid);
		input.setPhone(phone);
		input.setVcode(vcode);
		input.setMsgType(msgType);
		CheckVerificationCodeOutput output = (CheckVerificationCodeOutput) wizarposOpenRestClient.post(input, "/wechart/check/verification/code", CheckVerificationCodeOutput.class);
		if (output == null) {
			log.error("请求开放平台校验短信验证码接口失败");
			res.setCode(-1);
			res.setMessage("系统异常，请稍后重试");
			return res;
		} else if (SysConstants.OPEN_SUCCESS.equals(output.getCode())) { // 验证成功
			return res;
		} else if ("60096".equals(output.getCode())) {
			// 验证码错误
			res.setCode(1);
			res.setMessage("验证码错误");
			return res;
		} else if ("60097".equals(output.getCode())) {
			// 验证码已失效
			res.setCode(1);
			res.setMessage("验证码已失效");
			return res;
		} else if ("60098".equals(output.getCode())) {
			// 验证码已过期
			res.setCode(1);
			res.setMessage("验证码已过期");
			return res;
		} else {
			res.setCode(-1);
			res.setMessage("系统异常，请稍后重试");
			log.error("code；" + output.getCode());
			log.error("messages；" + output.getMessage());
			return res;
		}
	}
}
